@yume-chan/adb 0.0.23 → 1.0.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/CHANGELOG.md +51 -2
- package/LICENSE +1 -1
- package/README.md +4 -1
- package/esm/adb.d.ts +15 -9
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +5 -2
- package/esm/adb.js.map +1 -1
- package/esm/banner.d.ts +7 -6
- package/esm/banner.d.ts.map +1 -1
- package/esm/banner.js +6 -7
- package/esm/banner.js.map +1 -1
- package/esm/commands/framebuffer.d.ts +63 -34
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +35 -33
- package/esm/commands/framebuffer.js.map +1 -1
- package/esm/commands/power.d.ts.map +1 -1
- package/esm/commands/power.js +6 -5
- package/esm/commands/power.js.map +1 -1
- package/esm/commands/reverse.d.ts +12 -12
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +60 -39
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.js +3 -3
- package/esm/commands/subprocess/command.js.map +1 -1
- package/esm/commands/subprocess/protocols/none.d.ts +2 -2
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js +3 -5
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +22 -14
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +21 -27
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +8 -8
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/list.d.ts +49 -30
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +9 -11
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +7 -9
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +4 -6
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +25 -22
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +14 -21
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.d.ts +20 -23
- package/esm/commands/sync/request.d.ts.map +1 -1
- package/esm/commands/sync/request.js +26 -35
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +25 -19
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +49 -26
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +3 -3
- package/esm/commands/sync/socket.d.ts.map +1 -1
- package/esm/commands/sync/socket.js +10 -5
- package/esm/commands/sync/socket.js.map +1 -1
- package/esm/commands/sync/stat.d.ts +75 -54
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +73 -69
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +18 -17
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +8 -8
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts +0 -1
- package/esm/commands/tcpip.d.ts.map +1 -1
- package/esm/commands/tcpip.js +9 -9
- package/esm/commands/tcpip.js.map +1 -1
- package/esm/daemon/auth.d.ts +8 -7
- package/esm/daemon/auth.d.ts.map +1 -1
- package/esm/daemon/auth.js +8 -9
- package/esm/daemon/auth.js.map +1 -1
- package/esm/daemon/crypto.d.ts +4 -3
- package/esm/daemon/crypto.d.ts.map +1 -1
- package/esm/daemon/crypto.js +57 -49
- package/esm/daemon/crypto.js.map +1 -1
- package/esm/daemon/device.d.ts +2 -2
- package/esm/daemon/device.d.ts.map +1 -1
- package/esm/daemon/dispatcher.d.ts +35 -10
- package/esm/daemon/dispatcher.d.ts.map +1 -1
- package/esm/daemon/dispatcher.js +46 -33
- package/esm/daemon/dispatcher.js.map +1 -1
- package/esm/daemon/packet.d.ts +48 -32
- package/esm/daemon/packet.d.ts.map +1 -1
- package/esm/daemon/packet.js +36 -32
- package/esm/daemon/packet.js.map +1 -1
- package/esm/daemon/socket.d.ts +11 -11
- package/esm/daemon/socket.d.ts.map +1 -1
- package/esm/daemon/socket.js +19 -40
- package/esm/daemon/socket.js.map +1 -1
- package/esm/daemon/transport.d.ts +60 -20
- package/esm/daemon/transport.d.ts.map +1 -1
- package/esm/daemon/transport.js +12 -15
- package/esm/daemon/transport.js.map +1 -1
- package/esm/device-observer.d.ts +10 -0
- package/esm/device-observer.d.ts.map +1 -0
- package/esm/device-observer.js +2 -0
- package/esm/device-observer.js.map +1 -0
- package/esm/features.d.ts +12 -11
- package/esm/features.d.ts.map +1 -1
- package/esm/features.js +11 -12
- package/esm/features.js.map +1 -1
- package/esm/index.d.ts +1 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -0
- package/esm/index.js.map +1 -1
- package/esm/server/client.d.ts +140 -50
- package/esm/server/client.d.ts.map +1 -1
- package/esm/server/client.js +396 -180
- package/esm/server/client.js.map +1 -1
- package/esm/server/transport.d.ts +2 -2
- package/esm/server/transport.d.ts.map +1 -1
- package/esm/server/transport.js +4 -6
- package/esm/server/transport.js.map +1 -1
- package/esm/utils/base64.d.ts.map +1 -1
- package/esm/utils/base64.js +52 -38
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/hex.d.ts +1 -1
- package/esm/utils/hex.d.ts.map +1 -1
- package/esm/utils/hex.js +12 -14
- package/esm/utils/hex.js.map +1 -1
- package/esm/utils/index.d.ts +1 -1
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +1 -1
- package/esm/utils/index.js.map +1 -1
- package/esm/utils/no-op.d.ts.map +1 -1
- package/esm/utils/no-op.js +1 -0
- package/esm/utils/no-op.js.map +1 -1
- package/esm/utils/sequence-equal.d.ts +2 -0
- package/esm/utils/sequence-equal.d.ts.map +1 -0
- package/esm/utils/sequence-equal.js +12 -0
- package/esm/utils/sequence-equal.js.map +1 -0
- package/package.json +14 -19
- package/src/adb.ts +20 -11
- package/src/banner.ts +8 -6
- package/src/commands/framebuffer.ts +44 -35
- package/src/commands/power.ts +7 -5
- package/src/commands/reverse.ts +78 -47
- package/src/commands/subprocess/command.ts +3 -3
- package/src/commands/subprocess/protocols/none.ts +5 -7
- package/src/commands/subprocess/protocols/shell.ts +33 -35
- package/src/commands/subprocess/protocols/types.ts +8 -8
- package/src/commands/sync/list.ts +20 -15
- package/src/commands/sync/pull.ts +9 -8
- package/src/commands/sync/push.ts +25 -24
- package/src/commands/sync/request.ts +37 -38
- package/src/commands/sync/response.ts +63 -37
- package/src/commands/sync/socket.ts +13 -8
- package/src/commands/sync/stat.ts +93 -73
- package/src/commands/sync/sync.ts +12 -11
- package/src/commands/tcpip.ts +9 -9
- package/src/daemon/auth.ts +12 -10
- package/src/daemon/crypto.ts +66 -55
- package/src/daemon/device.ts +2 -2
- package/src/daemon/dispatcher.ts +106 -44
- package/src/daemon/packet.ts +57 -38
- package/src/daemon/socket.ts +30 -50
- package/src/daemon/transport.ts +98 -50
- package/src/device-observer.ts +10 -0
- package/src/features.ts +13 -11
- package/src/index.ts +1 -0
- package/src/server/client.ts +505 -268
- package/src/server/transport.ts +7 -9
- package/src/utils/base64.ts +59 -40
- package/src/utils/hex.ts +16 -14
- package/src/utils/index.ts +1 -1
- package/src/utils/no-op.ts +1 -0
- package/src/utils/sequence-equal.ts +13 -0
- package/tsconfig.build.json +1 -12
- package/tsconfig.build.tsbuildinfo +1 -1
- package/CHANGELOG.json +0 -265
- package/esm/utils/conditional-variable.d.ts +0 -8
- package/esm/utils/conditional-variable.d.ts.map +0 -1
- package/esm/utils/conditional-variable.js +0 -34
- package/esm/utils/conditional-variable.js.map +0 -1
- package/src/utils/conditional-variable.ts +0 -45
|
@@ -1,44 +1,53 @@
|
|
|
1
1
|
import { BufferedReadableStream } from "@yume-chan/stream-extra";
|
|
2
|
-
import
|
|
2
|
+
import type { StructValue } from "@yume-chan/struct";
|
|
3
|
+
import { buffer, struct, StructEmptyError, u32 } from "@yume-chan/struct";
|
|
3
4
|
|
|
4
5
|
import type { Adb } from "../adb.js";
|
|
5
6
|
|
|
6
|
-
const Version =
|
|
7
|
+
const Version = struct({ version: u32 }, { littleEndian: true });
|
|
7
8
|
|
|
8
|
-
export const AdbFrameBufferV1 =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
export const AdbFrameBufferV1 = struct(
|
|
10
|
+
{
|
|
11
|
+
bpp: u32,
|
|
12
|
+
size: u32,
|
|
13
|
+
width: u32,
|
|
14
|
+
height: u32,
|
|
15
|
+
red_offset: u32,
|
|
16
|
+
red_length: u32,
|
|
17
|
+
blue_offset: u32,
|
|
18
|
+
blue_length: u32,
|
|
19
|
+
green_offset: u32,
|
|
20
|
+
green_length: u32,
|
|
21
|
+
alpha_offset: u32,
|
|
22
|
+
alpha_length: u32,
|
|
23
|
+
data: buffer("size"),
|
|
24
|
+
},
|
|
25
|
+
{ littleEndian: true },
|
|
26
|
+
);
|
|
22
27
|
|
|
23
|
-
export type AdbFrameBufferV1 =
|
|
28
|
+
export type AdbFrameBufferV1 = StructValue<typeof AdbFrameBufferV1>;
|
|
24
29
|
|
|
25
|
-
export const AdbFrameBufferV2 =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
export const AdbFrameBufferV2 = struct(
|
|
31
|
+
{
|
|
32
|
+
bpp: u32,
|
|
33
|
+
colorSpace: u32,
|
|
34
|
+
size: u32,
|
|
35
|
+
width: u32,
|
|
36
|
+
height: u32,
|
|
37
|
+
red_offset: u32,
|
|
38
|
+
red_length: u32,
|
|
39
|
+
blue_offset: u32,
|
|
40
|
+
blue_length: u32,
|
|
41
|
+
green_offset: u32,
|
|
42
|
+
green_length: u32,
|
|
43
|
+
alpha_offset: u32,
|
|
44
|
+
alpha_length: u32,
|
|
45
|
+
data: buffer("size"),
|
|
46
|
+
},
|
|
47
|
+
{ littleEndian: true },
|
|
48
|
+
);
|
|
40
49
|
|
|
41
|
-
export type AdbFrameBufferV2 =
|
|
50
|
+
export type AdbFrameBufferV2 = StructValue<typeof AdbFrameBufferV2>;
|
|
42
51
|
|
|
43
52
|
/**
|
|
44
53
|
* ADB uses 8 int32 fields to describe bit depths
|
|
@@ -93,9 +102,9 @@ export async function framebuffer(adb: Adb): Promise<AdbFrameBuffer> {
|
|
|
93
102
|
switch (version) {
|
|
94
103
|
case 1:
|
|
95
104
|
// TODO: AdbFrameBuffer: does all v1 responses uses the same color space? Add it so the command returns same format for all versions.
|
|
96
|
-
return AdbFrameBufferV1.deserialize(stream);
|
|
105
|
+
return await AdbFrameBufferV1.deserialize(stream);
|
|
97
106
|
case 2:
|
|
98
|
-
return AdbFrameBufferV2.deserialize(stream);
|
|
107
|
+
return await AdbFrameBufferV2.deserialize(stream);
|
|
99
108
|
default:
|
|
100
109
|
throw new AdbFrameBufferUnsupportedVersionError(version);
|
|
101
110
|
}
|
package/src/commands/power.ts
CHANGED
|
@@ -40,11 +40,13 @@ export class AdbPower extends AdbCommandBase {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
powerButton(longPress = false) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
const args = ["input", "keyevent"];
|
|
44
|
+
if (longPress) {
|
|
45
|
+
args.push("--longpress");
|
|
46
|
+
}
|
|
47
|
+
args.push("POWER");
|
|
48
|
+
|
|
49
|
+
return this.adb.subprocess.spawnAndWaitLegacy(args);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/**
|
package/src/commands/reverse.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
// cspell: ignore killforward
|
|
2
2
|
|
|
3
|
-
import { AutoDisposable } from "@yume-chan/event";
|
|
4
3
|
import { BufferedReadableStream } from "@yume-chan/stream-extra";
|
|
5
|
-
import
|
|
4
|
+
import {
|
|
5
|
+
encodeUtf8,
|
|
6
|
+
ExactReadableEndedError,
|
|
7
|
+
string,
|
|
8
|
+
struct,
|
|
9
|
+
} from "@yume-chan/struct";
|
|
6
10
|
|
|
7
11
|
import type { Adb, AdbIncomingSocketHandler } from "../adb.js";
|
|
8
|
-
import {
|
|
12
|
+
import { hexToNumber, sequenceEqual } from "../utils/index.js";
|
|
9
13
|
|
|
10
14
|
export interface AdbForwardListener {
|
|
11
15
|
deviceSerial: string;
|
|
@@ -15,14 +19,25 @@ export interface AdbForwardListener {
|
|
|
15
19
|
remoteName: string;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
|
-
const AdbReverseStringResponse =
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
const AdbReverseStringResponse = struct(
|
|
23
|
+
{
|
|
24
|
+
length: string(4),
|
|
25
|
+
content: string({
|
|
26
|
+
field: "length",
|
|
27
|
+
convert(value: string) {
|
|
28
|
+
return Number.parseInt(value, 16);
|
|
29
|
+
},
|
|
30
|
+
back(value) {
|
|
31
|
+
return value.toString(16).padStart(4, "0");
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
},
|
|
35
|
+
{ littleEndian: true },
|
|
36
|
+
);
|
|
21
37
|
|
|
22
38
|
export class AdbReverseError extends Error {
|
|
23
39
|
constructor(message: string) {
|
|
24
40
|
super(message);
|
|
25
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
26
41
|
}
|
|
27
42
|
}
|
|
28
43
|
|
|
@@ -34,32 +49,44 @@ export class AdbReverseNotSupportedError extends AdbReverseError {
|
|
|
34
49
|
}
|
|
35
50
|
}
|
|
36
51
|
|
|
37
|
-
const AdbReverseErrorResponse =
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
const AdbReverseErrorResponse = struct(
|
|
53
|
+
/* #__PURE__ */ (() => AdbReverseStringResponse.fields)(),
|
|
54
|
+
{
|
|
55
|
+
littleEndian: true,
|
|
56
|
+
postDeserialize: (value) => {
|
|
57
|
+
// https://issuetracker.google.com/issues/37066218
|
|
58
|
+
// ADB on Android <9 can't create reverse tunnels when connected wirelessly (ADB over Wi-Fi),
|
|
59
|
+
// and returns this confusing "more than one device/emulator" error.
|
|
60
|
+
if (value.content === "more than one device/emulator") {
|
|
61
|
+
throw new AdbReverseNotSupportedError();
|
|
62
|
+
} else {
|
|
63
|
+
throw new AdbReverseError(value.content);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// Like `hexToNumber`, it's much faster than first converting `buffer` to a string
|
|
70
|
+
function decimalToNumber(buffer: Uint8Array) {
|
|
71
|
+
let value = 0;
|
|
72
|
+
for (const byte of buffer) {
|
|
73
|
+
// Like `parseInt`, return when it encounters a non-digit character
|
|
74
|
+
if (byte < 48 || byte > 57) {
|
|
75
|
+
return value;
|
|
47
76
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const buffer = await stream.readExactly(length);
|
|
52
|
-
return decodeUtf8(buffer);
|
|
77
|
+
value = value * 10 + byte - 48;
|
|
78
|
+
}
|
|
79
|
+
return value;
|
|
53
80
|
}
|
|
54
81
|
|
|
55
|
-
|
|
82
|
+
const OKAY = encodeUtf8("OKAY");
|
|
83
|
+
|
|
84
|
+
export class AdbReverseCommand {
|
|
56
85
|
protected adb: Adb;
|
|
57
86
|
|
|
58
87
|
readonly #deviceAddressToLocalAddress = new Map<string, string>();
|
|
59
88
|
|
|
60
89
|
constructor(adb: Adb) {
|
|
61
|
-
super();
|
|
62
|
-
|
|
63
90
|
this.adb = adb;
|
|
64
91
|
}
|
|
65
92
|
|
|
@@ -70,34 +97,37 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
70
97
|
|
|
71
98
|
protected async sendRequest(service: string) {
|
|
72
99
|
const stream = await this.createBufferedStream(service);
|
|
73
|
-
|
|
74
|
-
|
|
100
|
+
|
|
101
|
+
const response = await stream.readExactly(4);
|
|
102
|
+
if (!sequenceEqual(response, OKAY)) {
|
|
75
103
|
await AdbReverseErrorResponse.deserialize(stream);
|
|
76
104
|
}
|
|
105
|
+
|
|
77
106
|
return stream;
|
|
78
107
|
}
|
|
79
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Get a list of all reverse port forwarding on the device.
|
|
111
|
+
*/
|
|
80
112
|
async list(): Promise<AdbForwardListener[]> {
|
|
81
113
|
const stream = await this.createBufferedStream("reverse:list-forward");
|
|
82
114
|
|
|
83
115
|
const response = await AdbReverseStringResponse.deserialize(stream);
|
|
84
|
-
return response.content
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
116
|
+
return response.content
|
|
117
|
+
.split("\n")
|
|
118
|
+
.filter((line) => !!line)
|
|
119
|
+
.map((line) => {
|
|
120
|
+
const [deviceSerial, localName, remoteName] = line.split(
|
|
121
|
+
" ",
|
|
122
|
+
) as [string, string, string];
|
|
123
|
+
return { deviceSerial, localName, remoteName };
|
|
124
|
+
});
|
|
92
125
|
|
|
93
126
|
// No need to close the stream, device will close it
|
|
94
127
|
}
|
|
95
128
|
|
|
96
129
|
/**
|
|
97
|
-
* Add
|
|
98
|
-
* @param deviceAddress The address to be listened on device by ADB daemon. Or `tcp:0` to choose an available TCP port.
|
|
99
|
-
* @param localAddress The address that listens on the local machine.
|
|
100
|
-
* @returns `tcp:{ACTUAL_LISTENING_PORT}`, If `deviceAddress` is `tcp:0`; otherwise, `deviceAddress`.
|
|
130
|
+
* Add a reverse port forwarding for a program that already listens on a port.
|
|
101
131
|
*/
|
|
102
132
|
async addExternal(deviceAddress: string, localAddress: string) {
|
|
103
133
|
const stream = await this.sendRequest(
|
|
@@ -110,8 +140,8 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
110
140
|
const position = stream.position;
|
|
111
141
|
try {
|
|
112
142
|
const length = hexToNumber(await stream.readExactly(4));
|
|
113
|
-
const port = await
|
|
114
|
-
deviceAddress = `tcp:${
|
|
143
|
+
const port = decimalToNumber(await stream.readExactly(length));
|
|
144
|
+
deviceAddress = `tcp:${port}`;
|
|
115
145
|
} catch (e) {
|
|
116
146
|
if (
|
|
117
147
|
e instanceof ExactReadableEndedError &&
|
|
@@ -130,12 +160,7 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
130
160
|
}
|
|
131
161
|
|
|
132
162
|
/**
|
|
133
|
-
*
|
|
134
|
-
* @param handler A callback to handle incoming connections.
|
|
135
|
-
* @param localAddressThe The address that listens on the local machine. May be `undefined` to let the transport choose an appropriate one.
|
|
136
|
-
* @returns `tcp:{ACTUAL_LISTENING_PORT}`, If `deviceAddress` is `tcp:0`; otherwise, `deviceAddress`.
|
|
137
|
-
* @throws {AdbReverseNotSupportedError} If ADB reverse tunnel is not supported on this device when connected wirelessly.
|
|
138
|
-
* @throws {AdbReverseError} If ADB daemon returns an error.
|
|
163
|
+
* Add a reverse port forwarding.
|
|
139
164
|
*/
|
|
140
165
|
async add(
|
|
141
166
|
deviceAddress: string,
|
|
@@ -157,6 +182,9 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
157
182
|
}
|
|
158
183
|
}
|
|
159
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Remove a reverse port forwarding.
|
|
187
|
+
*/
|
|
160
188
|
async remove(deviceAddress: string): Promise<void> {
|
|
161
189
|
const localAddress =
|
|
162
190
|
this.#deviceAddressToLocalAddress.get(deviceAddress);
|
|
@@ -169,6 +197,9 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
169
197
|
// No need to close the stream, device will close it
|
|
170
198
|
}
|
|
171
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Remove all reverse port forwarding, including the ones added by other programs.
|
|
202
|
+
*/
|
|
172
203
|
async removeAll(): Promise<void> {
|
|
173
204
|
await this.adb.transport.clearReverseTunnels();
|
|
174
205
|
this.#deviceAddressToLocalAddress.clear();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConcatStringStream,
|
|
1
|
+
import { ConcatStringStream, TextDecoderStream } from "@yume-chan/stream-extra";
|
|
2
2
|
|
|
3
3
|
import { AdbCommandBase } from "../base.js";
|
|
4
4
|
|
|
@@ -112,10 +112,10 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
112
112
|
|
|
113
113
|
const [stdout, stderr, exitCode] = await Promise.all([
|
|
114
114
|
process.stdout
|
|
115
|
-
.pipeThrough(new
|
|
115
|
+
.pipeThrough(new TextDecoderStream())
|
|
116
116
|
.pipeThrough(new ConcatStringStream()),
|
|
117
117
|
process.stderr
|
|
118
|
-
.pipeThrough(new
|
|
118
|
+
.pipeThrough(new TextDecoderStream())
|
|
119
119
|
.pipeThrough(new ConcatStringStream()),
|
|
120
120
|
process.exit,
|
|
121
121
|
]);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MaybeConsumable, WritableStream } from "@yume-chan/stream-extra";
|
|
2
2
|
import { ReadableStream } from "@yume-chan/stream-extra";
|
|
3
3
|
|
|
4
4
|
import type { Adb, AdbSocket } from "../../../adb.js";
|
|
5
|
-
import { unreachable } from "../../../utils/index.js";
|
|
6
5
|
|
|
7
6
|
import type { AdbSubprocessProtocol } from "./types.js";
|
|
8
7
|
|
|
@@ -36,7 +35,7 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
|
36
35
|
readonly #socket: AdbSocket;
|
|
37
36
|
|
|
38
37
|
// Legacy shell forwards all data to stdin.
|
|
39
|
-
get stdin(): WritableStream<
|
|
38
|
+
get stdin(): WritableStream<MaybeConsumable<Uint8Array>> {
|
|
40
39
|
return this.#socket.writable;
|
|
41
40
|
}
|
|
42
41
|
|
|
@@ -64,10 +63,9 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
|
64
63
|
this.#socket = socket;
|
|
65
64
|
|
|
66
65
|
this.#stderr = new ReadableStream({
|
|
67
|
-
start: (controller) => {
|
|
68
|
-
this.#socket.closed
|
|
69
|
-
|
|
70
|
-
.catch(unreachable);
|
|
66
|
+
start: async (controller) => {
|
|
67
|
+
await this.#socket.closed;
|
|
68
|
+
controller.close();
|
|
71
69
|
},
|
|
72
70
|
});
|
|
73
71
|
this.#exit = socket.closed.then(() => 0);
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { PromiseResolver } from "@yume-chan/async";
|
|
2
2
|
import type {
|
|
3
|
-
Consumable,
|
|
4
3
|
PushReadableStreamController,
|
|
5
4
|
ReadableStream,
|
|
6
5
|
WritableStreamDefaultWriter,
|
|
7
6
|
} from "@yume-chan/stream-extra";
|
|
8
7
|
import {
|
|
9
|
-
|
|
8
|
+
MaybeConsumable,
|
|
10
9
|
PushReadableStream,
|
|
11
10
|
StructDeserializeStream,
|
|
12
11
|
WritableStream,
|
|
13
12
|
} from "@yume-chan/stream-extra";
|
|
14
|
-
import type {
|
|
15
|
-
import
|
|
13
|
+
import type { StructValue } from "@yume-chan/struct";
|
|
14
|
+
import { buffer, struct, u32, u8 } from "@yume-chan/struct";
|
|
16
15
|
|
|
17
16
|
import type { Adb, AdbSocket } from "../../../adb.js";
|
|
18
17
|
import { AdbFeature } from "../../../features.js";
|
|
@@ -20,22 +19,28 @@ import { encodeUtf8 } from "../../../utils/index.js";
|
|
|
20
19
|
|
|
21
20
|
import type { AdbSubprocessProtocol } from "./types.js";
|
|
22
21
|
|
|
23
|
-
export
|
|
24
|
-
Stdin,
|
|
25
|
-
Stdout,
|
|
26
|
-
Stderr,
|
|
27
|
-
Exit,
|
|
28
|
-
CloseStdin,
|
|
29
|
-
WindowSizeChange,
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
22
|
+
export const AdbShellProtocolId = {
|
|
23
|
+
Stdin: 0,
|
|
24
|
+
Stdout: 1,
|
|
25
|
+
Stderr: 2,
|
|
26
|
+
Exit: 3,
|
|
27
|
+
CloseStdin: 4,
|
|
28
|
+
WindowSizeChange: 5,
|
|
29
|
+
} as const;
|
|
30
|
+
|
|
31
|
+
export type AdbShellProtocolId =
|
|
32
|
+
(typeof AdbShellProtocolId)[keyof typeof AdbShellProtocolId];
|
|
33
|
+
|
|
34
|
+
// This packet format is used in both directions.
|
|
35
|
+
export const AdbShellProtocolPacket = struct(
|
|
36
|
+
{
|
|
37
|
+
id: u8<AdbShellProtocolId>(),
|
|
38
|
+
data: buffer(u32),
|
|
39
|
+
},
|
|
40
|
+
{ littleEndian: true },
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
type AdbShellProtocolPacket = StructValue<typeof AdbShellProtocolPacket>;
|
|
39
44
|
|
|
40
45
|
/**
|
|
41
46
|
* Shell v2 a.k.a Shell Protocol
|
|
@@ -64,9 +69,9 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
64
69
|
}
|
|
65
70
|
|
|
66
71
|
readonly #socket: AdbSocket;
|
|
67
|
-
#writer: WritableStreamDefaultWriter<
|
|
72
|
+
#writer: WritableStreamDefaultWriter<MaybeConsumable<Uint8Array>>;
|
|
68
73
|
|
|
69
|
-
#stdin: WritableStream<
|
|
74
|
+
#stdin: WritableStream<MaybeConsumable<Uint8Array>>;
|
|
70
75
|
get stdin() {
|
|
71
76
|
return this.#stdin;
|
|
72
77
|
}
|
|
@@ -108,14 +113,10 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
108
113
|
this.#exit.resolve(chunk.data[0]!);
|
|
109
114
|
break;
|
|
110
115
|
case AdbShellProtocolId.Stdout:
|
|
111
|
-
|
|
112
|
-
await stdoutController.enqueue(chunk.data);
|
|
113
|
-
}
|
|
116
|
+
await stdoutController.enqueue(chunk.data);
|
|
114
117
|
break;
|
|
115
118
|
case AdbShellProtocolId.Stderr:
|
|
116
|
-
|
|
117
|
-
await stderrController.enqueue(chunk.data);
|
|
118
|
-
}
|
|
119
|
+
await stderrController.enqueue(chunk.data);
|
|
119
120
|
break;
|
|
120
121
|
}
|
|
121
122
|
},
|
|
@@ -140,23 +141,20 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
140
141
|
|
|
141
142
|
this.#writer = this.#socket.writable.getWriter();
|
|
142
143
|
|
|
143
|
-
this.#stdin = new WritableStream<
|
|
144
|
+
this.#stdin = new MaybeConsumable.WritableStream<Uint8Array>({
|
|
144
145
|
write: async (chunk) => {
|
|
145
|
-
await
|
|
146
|
-
this.#writer,
|
|
146
|
+
await this.#writer.write(
|
|
147
147
|
AdbShellProtocolPacket.serialize({
|
|
148
148
|
id: AdbShellProtocolId.Stdin,
|
|
149
|
-
data: chunk
|
|
149
|
+
data: chunk,
|
|
150
150
|
}),
|
|
151
151
|
);
|
|
152
|
-
chunk.consume();
|
|
153
152
|
},
|
|
154
153
|
});
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
async resize(rows: number, cols: number) {
|
|
158
|
-
await
|
|
159
|
-
this.#writer,
|
|
157
|
+
await this.#writer.write(
|
|
160
158
|
AdbShellProtocolPacket.serialize({
|
|
161
159
|
id: AdbShellProtocolId.WindowSizeChange,
|
|
162
160
|
// The "correct" format is `${rows}x${cols},${x_pixels}x${y_pixels}`
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import type { MaybePromiseLike } from "@yume-chan/async";
|
|
1
2
|
import type {
|
|
2
|
-
|
|
3
|
+
MaybeConsumable,
|
|
3
4
|
ReadableStream,
|
|
4
5
|
WritableStream,
|
|
5
6
|
} from "@yume-chan/stream-extra";
|
|
6
|
-
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
7
7
|
|
|
8
8
|
import type { Adb, AdbSocket } from "../../../adb.js";
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@ export interface AdbSubprocessProtocol {
|
|
|
11
11
|
/**
|
|
12
12
|
* A WritableStream that writes to the `stdin` stream.
|
|
13
13
|
*/
|
|
14
|
-
readonly stdin: WritableStream<
|
|
14
|
+
readonly stdin: WritableStream<MaybeConsumable<Uint8Array>>;
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* The `stdout` stream of the process.
|
|
@@ -40,23 +40,23 @@ export interface AdbSubprocessProtocol {
|
|
|
40
40
|
* Some `AdbSubprocessProtocol`s may not support resizing
|
|
41
41
|
* and will ignore calls to this method.
|
|
42
42
|
*/
|
|
43
|
-
resize(rows: number, cols: number):
|
|
43
|
+
resize(rows: number, cols: number): MaybePromiseLike<void>;
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* Kills the current process.
|
|
47
47
|
*/
|
|
48
|
-
kill():
|
|
48
|
+
kill(): MaybePromiseLike<void>;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export interface AdbSubprocessProtocolConstructor {
|
|
52
52
|
/** Returns `true` if the `adb` instance supports this shell */
|
|
53
|
-
isSupported(adb: Adb):
|
|
53
|
+
isSupported(adb: Adb): MaybePromiseLike<boolean>;
|
|
54
54
|
|
|
55
55
|
/** Spawns an executable in PTY (interactive) mode. */
|
|
56
|
-
pty(adb: Adb, command: string):
|
|
56
|
+
pty(adb: Adb, command: string): MaybePromiseLike<AdbSubprocessProtocol>;
|
|
57
57
|
|
|
58
58
|
/** Spawns an executable and pipe the output. */
|
|
59
|
-
raw(adb: Adb, command: string):
|
|
59
|
+
raw(adb: Adb, command: string): MaybePromiseLike<AdbSubprocessProtocol>;
|
|
60
60
|
|
|
61
61
|
/** Creates a new `AdbShell` by attaching to an exist `AdbSocket` */
|
|
62
62
|
new (socket: AdbSocket): AdbSubprocessProtocol;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { StructValue } from "@yume-chan/struct";
|
|
2
|
+
import { string, struct, u32 } from "@yume-chan/struct";
|
|
2
3
|
|
|
3
4
|
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|
4
5
|
import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
|
|
@@ -14,23 +15,27 @@ export interface AdbSyncEntry extends AdbSyncStat {
|
|
|
14
15
|
name: string;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
export const AdbSyncEntryResponse =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
export const AdbSyncEntryResponse = /* #__PURE__ */ (() =>
|
|
19
|
+
struct(
|
|
20
|
+
{
|
|
21
|
+
...AdbSyncLstatResponse.fields,
|
|
22
|
+
name: string(u32),
|
|
23
|
+
},
|
|
24
|
+
{ littleEndian: true, extra: AdbSyncLstatResponse.extra },
|
|
25
|
+
))();
|
|
22
26
|
|
|
23
|
-
export type AdbSyncEntryResponse =
|
|
24
|
-
(typeof AdbSyncEntryResponse)["TDeserializeResult"];
|
|
27
|
+
export type AdbSyncEntryResponse = StructValue<typeof AdbSyncEntryResponse>;
|
|
25
28
|
|
|
26
|
-
export const AdbSyncEntry2Response =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
export const AdbSyncEntry2Response = /* #__PURE__ */ (() =>
|
|
30
|
+
struct(
|
|
31
|
+
{
|
|
32
|
+
...AdbSyncStatResponse.fields,
|
|
33
|
+
name: string(u32),
|
|
34
|
+
},
|
|
35
|
+
{ littleEndian: true, extra: AdbSyncStatResponse.extra },
|
|
36
|
+
))();
|
|
31
37
|
|
|
32
|
-
export type AdbSyncEntry2Response =
|
|
33
|
-
(typeof AdbSyncEntry2Response)["TDeserializeResult"];
|
|
38
|
+
export type AdbSyncEntry2Response = StructValue<typeof AdbSyncEntry2Response>;
|
|
34
39
|
|
|
35
40
|
export async function* adbSyncOpenDirV2(
|
|
36
41
|
socket: AdbSyncSocket,
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import type { ReadableStream } from "@yume-chan/stream-extra";
|
|
2
2
|
import { PushReadableStream } from "@yume-chan/stream-extra";
|
|
3
|
-
import
|
|
3
|
+
import type { StructValue } from "@yume-chan/struct";
|
|
4
|
+
import { buffer, struct, u32 } from "@yume-chan/struct";
|
|
4
5
|
|
|
5
6
|
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|
6
|
-
import {
|
|
7
|
+
import { adbSyncReadResponses, AdbSyncResponseId } from "./response.js";
|
|
7
8
|
import type { AdbSyncSocket } from "./socket.js";
|
|
8
9
|
|
|
9
|
-
export const AdbSyncDataResponse =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
export const AdbSyncDataResponse = struct(
|
|
11
|
+
{ data: buffer(u32) },
|
|
12
|
+
{ littleEndian: true },
|
|
13
|
+
);
|
|
13
14
|
|
|
14
|
-
export type AdbSyncDataResponse =
|
|
15
|
-
(typeof AdbSyncDataResponse)["TDeserializeResult"];
|
|
15
|
+
export type AdbSyncDataResponse = StructValue<typeof AdbSyncDataResponse>;
|
|
16
16
|
|
|
17
17
|
export async function* adbSyncPullGenerator(
|
|
18
18
|
socket: AdbSyncSocket,
|
|
@@ -52,6 +52,7 @@ export function adbSyncPull(
|
|
|
52
52
|
socket: AdbSyncSocket,
|
|
53
53
|
path: string,
|
|
54
54
|
): ReadableStream<Uint8Array> {
|
|
55
|
+
// TODO: use `ReadableStream.from` when it's supported
|
|
55
56
|
return new PushReadableStream(async (controller) => {
|
|
56
57
|
for await (const data of adbSyncPullGenerator(socket, path)) {
|
|
57
58
|
await controller.enqueue(data);
|