@yume-chan/adb 0.0.15 → 0.0.17
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 +33 -0
- package/CHANGELOG.md +18 -1
- package/LICENSE +21 -21
- package/README.md +247 -247
- package/esm/adb.d.ts +15 -3
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +18 -6
- package/esm/adb.js.map +1 -1
- package/esm/auth.d.ts.map +1 -1
- package/esm/auth.js.map +1 -1
- package/esm/backend.d.ts +2 -2
- package/esm/backend.d.ts.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 +17 -1
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +4 -15
- package/esm/commands/framebuffer.js.map +1 -1
- package/esm/commands/install.d.ts +2 -2
- package/esm/commands/install.d.ts.map +1 -1
- package/esm/commands/install.js +3 -2
- package/esm/commands/install.js.map +1 -1
- package/esm/commands/power.d.ts +1 -1
- package/esm/commands/power.js +1 -1
- package/esm/commands/reverse.d.ts +3 -3
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +9 -9
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.d.ts +52 -0
- package/esm/commands/subprocess/command.d.ts.map +1 -0
- package/esm/commands/subprocess/command.js +83 -0
- package/esm/commands/subprocess/command.js.map +1 -0
- package/esm/commands/subprocess/index.d.ts +1 -53
- package/esm/commands/subprocess/index.d.ts.map +1 -1
- package/esm/commands/subprocess/index.js +1 -85
- package/esm/commands/subprocess/index.js.map +1 -1
- package/esm/commands/subprocess/protocols/none.d.ts +5 -4
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js +11 -8
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +4 -4
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +6 -6
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +7 -7
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/index.d.ts +1 -1
- package/esm/commands/sync/index.d.ts.map +1 -1
- package/esm/commands/sync/index.js +1 -1
- package/esm/commands/sync/index.js.map +1 -1
- package/esm/commands/sync/list.d.ts +2 -2
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +15 -43
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +3 -2
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +15 -17
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +2 -2
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +2 -5
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.d.ts +1 -1
- package/esm/commands/sync/request.d.ts.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 +4 -9
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +32 -23
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/stat.d.ts +3 -3
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +13 -30
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +2 -2
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +7 -5
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/crypto.js +1 -1
- package/esm/crypto.js.map +1 -1
- package/esm/index.d.ts +0 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +0 -1
- package/esm/index.js.map +1 -1
- package/esm/packet.d.ts +1 -1
- package/esm/packet.d.ts.map +1 -1
- package/esm/packet.js +1 -1
- package/esm/packet.js.map +1 -1
- package/esm/socket/dispatcher.d.ts +11 -3
- package/esm/socket/dispatcher.d.ts.map +1 -1
- package/esm/socket/dispatcher.js +19 -11
- package/esm/socket/dispatcher.js.map +1 -1
- package/esm/socket/index.d.ts +1 -1
- package/esm/socket/index.d.ts.map +1 -1
- package/esm/socket/index.js +1 -1
- package/esm/socket/index.js.map +1 -1
- package/esm/socket/socket.d.ts +9 -4
- package/esm/socket/socket.d.ts.map +1 -1
- package/esm/socket/socket.js +20 -10
- package/esm/socket/socket.js.map +1 -1
- package/esm/utils/base64.d.ts +23 -0
- package/esm/utils/base64.d.ts.map +1 -1
- package/esm/utils/base64.js +6 -0
- package/esm/utils/base64.js.map +1 -1
- package/package.json +13 -14
- package/src/adb.ts +285 -273
- package/src/auth.ts +174 -173
- package/src/backend.ts +12 -11
- package/src/commands/base.ts +12 -11
- package/src/commands/framebuffer.ts +78 -73
- package/src/commands/index.ts +8 -8
- package/src/commands/install.ts +32 -30
- package/src/commands/power.ts +54 -54
- package/src/commands/reverse.ts +141 -140
- package/src/commands/subprocess/command.ts +131 -0
- package/src/commands/subprocess/index.ts +3 -139
- package/src/commands/subprocess/protocols/none.ts +73 -68
- package/src/commands/subprocess/protocols/shell.ts +191 -190
- package/src/commands/subprocess/protocols/types.ts +60 -59
- package/src/commands/subprocess/utils.ts +20 -20
- package/src/commands/sync/index.ts +7 -7
- package/src/commands/sync/list.ts +54 -86
- package/src/commands/sync/pull.ts +45 -46
- package/src/commands/sync/push.ts +38 -41
- package/src/commands/sync/request.ts +51 -50
- package/src/commands/sync/response.ts +68 -64
- package/src/commands/sync/stat.ts +129 -150
- package/src/commands/sync/sync.ts +182 -181
- package/src/commands/tcpip.ts +21 -21
- package/src/crypto.ts +296 -296
- package/src/features.ts +9 -9
- package/src/index.ts +10 -11
- package/src/packet.ts +80 -80
- package/src/socket/dispatcher.ts +310 -304
- package/src/socket/index.ts +2 -2
- package/src/socket/socket.ts +156 -144
- package/src/utils/auto-reset-event.ts +41 -41
- package/src/utils/base64.ts +329 -306
- package/src/utils/index.ts +3 -3
- package/tsconfig.build.json +3 -3
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/commands/subprocess/legacy.d.ts +0 -35
- package/esm/commands/subprocess/legacy.d.ts.map +0 -1
- package/esm/commands/subprocess/legacy.js +0 -53
- package/esm/commands/subprocess/legacy.js.map +0 -1
- package/esm/commands/subprocess/protocol.d.ts +0 -39
- package/esm/commands/subprocess/protocol.d.ts.map +0 -1
- package/esm/commands/subprocess/protocol.js +0 -157
- package/esm/commands/subprocess/protocol.js.map +0 -1
- package/esm/commands/subprocess/types.d.ts +0 -50
- package/esm/commands/subprocess/types.d.ts.map +0 -1
- package/esm/commands/subprocess/types.js +0 -2
- package/esm/commands/subprocess/types.js.map +0 -1
- package/esm/socket/controller.d.ts +0 -37
- package/esm/socket/controller.d.ts.map +0 -1
- package/esm/socket/controller.js +0 -66
- package/esm/socket/controller.js.map +0 -1
- package/esm/stream/buffered.d.ts +0 -35
- package/esm/stream/buffered.d.ts.map +0 -1
- package/esm/stream/buffered.js +0 -123
- package/esm/stream/buffered.js.map +0 -1
- package/esm/stream/detect.bak.d.ts +0 -240
- package/esm/stream/detect.bak.d.ts.map +0 -1
- package/esm/stream/detect.bak.js +0 -60
- package/esm/stream/detect.bak.js.map +0 -1
- package/esm/stream/detect.d.ts +0 -2
- package/esm/stream/detect.d.ts.map +0 -1
- package/esm/stream/detect.js +0 -5
- package/esm/stream/detect.js.map +0 -1
- package/esm/stream/detect.native.d.ts +0 -240
- package/esm/stream/detect.native.d.ts.map +0 -1
- package/esm/stream/detect.native.js +0 -60
- package/esm/stream/detect.native.js.map +0 -1
- package/esm/stream/detect.polyfill.d.ts +0 -18
- package/esm/stream/detect.polyfill.d.ts.map +0 -1
- package/esm/stream/detect.polyfill.js +0 -9
- package/esm/stream/detect.polyfill.js.map +0 -1
- package/esm/stream/index.d.ts +0 -4
- package/esm/stream/index.d.ts.map +0 -1
- package/esm/stream/index.js +0 -4
- package/esm/stream/index.js.map +0 -1
- package/esm/stream/transform.d.ts +0 -104
- package/esm/stream/transform.d.ts.map +0 -1
- package/esm/stream/transform.js +0 -373
- package/esm/stream/transform.js.map +0 -1
- package/esm/utils/encoding.d.ts +0 -3
- package/esm/utils/encoding.d.ts.map +0 -1
- package/esm/utils/encoding.js +0 -11
- package/esm/utils/encoding.js.map +0 -1
- package/src/stream/buffered.ts +0 -147
- package/src/stream/detect.native.ts +0 -362
- package/src/stream/detect.polyfill.ts +0 -28
- package/src/stream/detect.ts +0 -5
- package/src/stream/index.ts +0 -3
- package/src/stream/transform.ts +0 -447
- package/tsconfig.test.json +0 -10
package/src/commands/power.ts
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
// cspell: ignore bootloader
|
|
2
|
-
// cspell: ignore fastboot
|
|
3
|
-
// cspell: ignore keyevent
|
|
4
|
-
// cspell: ignore longpress
|
|
5
|
-
|
|
6
|
-
import { AdbCommandBase } from
|
|
7
|
-
|
|
8
|
-
export class AdbPower extends AdbCommandBase {
|
|
9
|
-
public reboot(name: string = '') {
|
|
10
|
-
return this.adb.createSocketAndWait(`reboot:${name}`);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
public bootloader() {
|
|
14
|
-
return this.reboot('bootloader');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
public fastboot() {
|
|
18
|
-
return this.reboot('fastboot');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
public recovery() {
|
|
22
|
-
return this.reboot('recovery');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
public sideload() {
|
|
26
|
-
return this.reboot('sideload');
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Reboot to Qualcomm Emergency Download (EDL) Mode.
|
|
31
|
-
*
|
|
32
|
-
* Only works on some Qualcomm devices.
|
|
33
|
-
*/
|
|
34
|
-
public qualcommEdlMode() {
|
|
35
|
-
return this.reboot('edl');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
public powerOff() {
|
|
39
|
-
return this.adb.subprocess.spawnAndWaitLegacy(['reboot', '-p']);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
public powerButton(longPress: boolean = false) {
|
|
43
|
-
return this.adb.subprocess.spawnAndWaitLegacy(['input', 'keyevent', longPress ? '--longpress POWER' : 'POWER']);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Reboot to Samsung Odin download mode.
|
|
48
|
-
*
|
|
49
|
-
* Only works on Samsung devices.
|
|
50
|
-
*/
|
|
51
|
-
public samsungOdin() {
|
|
52
|
-
return this.reboot('download');
|
|
53
|
-
}
|
|
54
|
-
}
|
|
1
|
+
// cspell: ignore bootloader
|
|
2
|
+
// cspell: ignore fastboot
|
|
3
|
+
// cspell: ignore keyevent
|
|
4
|
+
// cspell: ignore longpress
|
|
5
|
+
|
|
6
|
+
import { AdbCommandBase } from './base.js';
|
|
7
|
+
|
|
8
|
+
export class AdbPower extends AdbCommandBase {
|
|
9
|
+
public reboot(name: string = '') {
|
|
10
|
+
return this.adb.createSocketAndWait(`reboot:${name}`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public bootloader() {
|
|
14
|
+
return this.reboot('bootloader');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public fastboot() {
|
|
18
|
+
return this.reboot('fastboot');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public recovery() {
|
|
22
|
+
return this.reboot('recovery');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public sideload() {
|
|
26
|
+
return this.reboot('sideload');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Reboot to Qualcomm Emergency Download (EDL) Mode.
|
|
31
|
+
*
|
|
32
|
+
* Only works on some Qualcomm devices.
|
|
33
|
+
*/
|
|
34
|
+
public qualcommEdlMode() {
|
|
35
|
+
return this.reboot('edl');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public powerOff() {
|
|
39
|
+
return this.adb.subprocess.spawnAndWaitLegacy(['reboot', '-p']);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public powerButton(longPress: boolean = false) {
|
|
43
|
+
return this.adb.subprocess.spawnAndWaitLegacy(['input', 'keyevent', longPress ? '--longpress POWER' : 'POWER']);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Reboot to Samsung Odin download mode.
|
|
48
|
+
*
|
|
49
|
+
* Only works on Samsung devices.
|
|
50
|
+
*/
|
|
51
|
+
public samsungOdin() {
|
|
52
|
+
return this.reboot('download');
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/commands/reverse.ts
CHANGED
|
@@ -1,140 +1,141 @@
|
|
|
1
|
-
// cspell: ignore killforward
|
|
2
|
-
|
|
3
|
-
import { AutoDisposable } from '@yume-chan/event';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
.string('
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
this.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
* @param
|
|
82
|
-
* @param handler
|
|
83
|
-
* @
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
this.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
this.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
this.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
1
|
+
// cspell: ignore killforward
|
|
2
|
+
|
|
3
|
+
import { AutoDisposable } from '@yume-chan/event';
|
|
4
|
+
import { BufferedReadableStream, BufferedReadableStreamEndedError } from '@yume-chan/stream-extra';
|
|
5
|
+
import Struct from '@yume-chan/struct';
|
|
6
|
+
|
|
7
|
+
import type { Adb } from '../adb.js';
|
|
8
|
+
import type { AdbIncomingSocketHandler, AdbSocket } from '../socket/index.js';
|
|
9
|
+
import { decodeUtf8 } from '../utils/index.js';
|
|
10
|
+
|
|
11
|
+
export interface AdbForwardListener {
|
|
12
|
+
deviceSerial: string;
|
|
13
|
+
|
|
14
|
+
localName: string;
|
|
15
|
+
|
|
16
|
+
remoteName: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const AdbReverseStringResponse =
|
|
20
|
+
new Struct()
|
|
21
|
+
.string('length', { length: 4 })
|
|
22
|
+
.string('content', { lengthField: 'length', lengthFieldRadix: 16 });
|
|
23
|
+
|
|
24
|
+
const AdbReverseErrorResponse =
|
|
25
|
+
new Struct()
|
|
26
|
+
.fields(AdbReverseStringResponse)
|
|
27
|
+
.postDeserialize((value) => {
|
|
28
|
+
throw new Error(value.content);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export class AdbReverseCommand extends AutoDisposable {
|
|
32
|
+
protected localAddressToHandler = new Map<string, AdbIncomingSocketHandler>();
|
|
33
|
+
|
|
34
|
+
protected deviceAddressToLocalAddress = new Map<string, string>();
|
|
35
|
+
|
|
36
|
+
protected adb: Adb;
|
|
37
|
+
|
|
38
|
+
protected listening = false;
|
|
39
|
+
|
|
40
|
+
public constructor(adb: Adb) {
|
|
41
|
+
super();
|
|
42
|
+
|
|
43
|
+
this.adb = adb;
|
|
44
|
+
this.addDisposable(this.adb.onIncomingSocket(this.handleIncomingSocket));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
protected handleIncomingSocket = async (socket: AdbSocket) => {
|
|
48
|
+
let address = socket.serviceString;
|
|
49
|
+
// ADB daemon appends `\0` to the service string
|
|
50
|
+
address = address.replace(/\0/g, '');
|
|
51
|
+
return !!(await this.localAddressToHandler.get(address)?.(socket));
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
private async createBufferedStream(service: string) {
|
|
55
|
+
const socket = await this.adb.createSocket(service);
|
|
56
|
+
return new BufferedReadableStream(socket.readable);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private async sendRequest(service: string) {
|
|
60
|
+
const stream = await this.createBufferedStream(service);
|
|
61
|
+
const success = decodeUtf8(await stream.read(4)) === 'OKAY';
|
|
62
|
+
if (!success) {
|
|
63
|
+
await AdbReverseErrorResponse.deserialize(stream);
|
|
64
|
+
}
|
|
65
|
+
return stream;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public async list(): Promise<AdbForwardListener[]> {
|
|
69
|
+
const stream = await this.createBufferedStream('reverse:list-forward');
|
|
70
|
+
|
|
71
|
+
const response = await AdbReverseStringResponse.deserialize(stream);
|
|
72
|
+
return response.content!.split('\n').map(line => {
|
|
73
|
+
const [deviceSerial, localName, remoteName] = line.split(' ') as [string, string, string];
|
|
74
|
+
return { deviceSerial, localName, remoteName };
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// No need to close the stream, device will close it
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param deviceAddress The address adbd on device is listening on. Can be `tcp:0` to let adbd choose an available TCP port by itself.
|
|
82
|
+
* @param localAddress Native ADB client will open a connection to this address when reverse connection received. In WebADB, it's only used to uniquely identify a reverse tunnel registry, `handler` will be called to handle the connection.
|
|
83
|
+
* @param handler A callback to handle incoming connections. It must return `true` if it accepts the connection.
|
|
84
|
+
* @returns `tcp:{ACTUAL_LISTENING_PORT}`, If `deviceAddress` is `tcp:0`; otherwise, `deviceAddress`.
|
|
85
|
+
*/
|
|
86
|
+
public async add(
|
|
87
|
+
deviceAddress: string,
|
|
88
|
+
localAddress: string,
|
|
89
|
+
handler: AdbIncomingSocketHandler,
|
|
90
|
+
): Promise<string> {
|
|
91
|
+
const stream = await this.sendRequest(`reverse:forward:${deviceAddress};${localAddress}`);
|
|
92
|
+
|
|
93
|
+
// `tcp:0` tells the device to pick an available port.
|
|
94
|
+
// On Android >=8, device will respond with the selected port for all `tcp:` requests.
|
|
95
|
+
if (deviceAddress.startsWith('tcp:')) {
|
|
96
|
+
let length: number | undefined;
|
|
97
|
+
try {
|
|
98
|
+
length = Number.parseInt(decodeUtf8(await stream.read(4)), 16);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
if (!(e instanceof BufferedReadableStreamEndedError)) {
|
|
101
|
+
throw e;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Android <8 doesn't have this response.
|
|
105
|
+
// (the stream is closed now)
|
|
106
|
+
// Can be safely ignored.
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (length !== undefined) {
|
|
110
|
+
const port = decodeUtf8(await stream.read(length!));
|
|
111
|
+
deviceAddress = `tcp:${Number.parseInt(port, 10)}`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this.localAddressToHandler.set(localAddress, handler);
|
|
116
|
+
this.deviceAddressToLocalAddress.set(deviceAddress, localAddress);
|
|
117
|
+
return deviceAddress;
|
|
118
|
+
|
|
119
|
+
// No need to close the stream, device will close it
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public async remove(deviceAddress: string): Promise<void> {
|
|
123
|
+
await this.sendRequest(`reverse:killforward:${deviceAddress}`);
|
|
124
|
+
|
|
125
|
+
if (this.deviceAddressToLocalAddress.has(deviceAddress)) {
|
|
126
|
+
this.localAddressToHandler.delete(this.deviceAddressToLocalAddress.get(deviceAddress)!);
|
|
127
|
+
this.deviceAddressToLocalAddress.delete(deviceAddress);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// No need to close the stream, device will close it
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public async removeAll(): Promise<void> {
|
|
134
|
+
await this.sendRequest(`reverse:killforward-all`);
|
|
135
|
+
|
|
136
|
+
this.deviceAddressToLocalAddress.clear();
|
|
137
|
+
this.localAddressToHandler.clear();
|
|
138
|
+
|
|
139
|
+
// No need to close the stream, device will close it
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { GatherStringStream, DecodeUtf8Stream } from '@yume-chan/stream-extra';
|
|
2
|
+
|
|
3
|
+
import { AdbCommandBase } from '../base.js';
|
|
4
|
+
import { AdbSubprocessNoneProtocol, AdbSubprocessProtocol, AdbSubprocessProtocolConstructor, AdbSubprocessShellProtocol } from './protocols/index.js';
|
|
5
|
+
|
|
6
|
+
export interface AdbSubprocessOptions {
|
|
7
|
+
/**
|
|
8
|
+
* A list of `AdbSubprocessProtocolConstructor`s to be used.
|
|
9
|
+
*
|
|
10
|
+
* Different `AdbSubprocessProtocol` has different capabilities, thus requires specific adaptations.
|
|
11
|
+
* Check their documentations for details.
|
|
12
|
+
*
|
|
13
|
+
* The first protocol whose `isSupported` returns `true` will be used.
|
|
14
|
+
* If no `AdbSubprocessProtocol` is supported, an error will be thrown.
|
|
15
|
+
*
|
|
16
|
+
* @default [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol]
|
|
17
|
+
*/
|
|
18
|
+
protocols: AdbSubprocessProtocolConstructor[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const DEFAULT_OPTIONS: AdbSubprocessOptions = {
|
|
22
|
+
protocols: [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export interface AdbSubprocessWaitResult {
|
|
26
|
+
stdout: string;
|
|
27
|
+
stderr: string;
|
|
28
|
+
exitCode: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class AdbSubprocess extends AdbCommandBase {
|
|
32
|
+
private async createProtocol(
|
|
33
|
+
mode: 'pty' | 'raw',
|
|
34
|
+
command?: string | string[],
|
|
35
|
+
options?: Partial<AdbSubprocessOptions>
|
|
36
|
+
): Promise<AdbSubprocessProtocol> {
|
|
37
|
+
const { protocols } = { ...DEFAULT_OPTIONS, ...options };
|
|
38
|
+
|
|
39
|
+
let Constructor: AdbSubprocessProtocolConstructor | undefined;
|
|
40
|
+
for (const item of protocols) {
|
|
41
|
+
// It's async so can't use `Array#find`
|
|
42
|
+
if (await item.isSupported(this.adb)) {
|
|
43
|
+
Constructor = item;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!Constructor) {
|
|
49
|
+
throw new Error('No specified protocol is supported by the device');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (Array.isArray(command)) {
|
|
53
|
+
command = command.join(' ');
|
|
54
|
+
} else if (command === undefined) {
|
|
55
|
+
// spawn the default shell
|
|
56
|
+
command = '';
|
|
57
|
+
}
|
|
58
|
+
return await Constructor[mode](this.adb, command);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Spawns an executable in PTY (interactive) mode.
|
|
63
|
+
* @param command The command to run. If omitted, the default shell will be spawned.
|
|
64
|
+
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
65
|
+
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
|
66
|
+
*/
|
|
67
|
+
public shell(
|
|
68
|
+
command?: string | string[],
|
|
69
|
+
options?: Partial<AdbSubprocessOptions>
|
|
70
|
+
): Promise<AdbSubprocessProtocol> {
|
|
71
|
+
return this.createProtocol('pty', command, options);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Spawns an executable and pipe the output.
|
|
76
|
+
* @param command The command to run, or an array of strings containing both command and args.
|
|
77
|
+
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
78
|
+
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
|
79
|
+
*/
|
|
80
|
+
public spawn(
|
|
81
|
+
command: string | string[],
|
|
82
|
+
options?: Partial<AdbSubprocessOptions>
|
|
83
|
+
): Promise<AdbSubprocessProtocol> {
|
|
84
|
+
return this.createProtocol('raw', command, options);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Spawns a new process, waits until it exits, and returns the entire output.
|
|
89
|
+
* @param command The command to run
|
|
90
|
+
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
91
|
+
* @returns The entire output of the command
|
|
92
|
+
*/
|
|
93
|
+
public async spawnAndWait(
|
|
94
|
+
command: string | string[],
|
|
95
|
+
options?: Partial<AdbSubprocessOptions>
|
|
96
|
+
): Promise<AdbSubprocessWaitResult> {
|
|
97
|
+
const shell = await this.spawn(command, options);
|
|
98
|
+
|
|
99
|
+
const stdout = new GatherStringStream();
|
|
100
|
+
const stderr = new GatherStringStream();
|
|
101
|
+
|
|
102
|
+
const [, , exitCode] = await Promise.all([
|
|
103
|
+
shell.stdout
|
|
104
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
105
|
+
.pipeTo(stdout),
|
|
106
|
+
shell.stderr
|
|
107
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
108
|
+
.pipeTo(stderr),
|
|
109
|
+
shell.exit
|
|
110
|
+
]);
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
stdout: stdout.result,
|
|
114
|
+
stderr: stderr.result,
|
|
115
|
+
exitCode,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Spawns a new process, waits until it exits, and returns the entire output.
|
|
121
|
+
* @param command The command to run
|
|
122
|
+
* @returns The entire output of the command
|
|
123
|
+
*/
|
|
124
|
+
public async spawnAndWaitLegacy(command: string | string[]): Promise<string> {
|
|
125
|
+
const { stdout } = await this.spawnAndWait(
|
|
126
|
+
command,
|
|
127
|
+
{ protocols: [AdbSubprocessNoneProtocol] }
|
|
128
|
+
);
|
|
129
|
+
return stdout;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -1,139 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export * from './protocols/index.js';
|
|
6
|
-
export * from './utils.js';
|
|
7
|
-
|
|
8
|
-
export interface AdbSubprocessOptions {
|
|
9
|
-
/**
|
|
10
|
-
* A list of `AdbSubprocessProtocolConstructor`s to be used.
|
|
11
|
-
*
|
|
12
|
-
* Different `AdbSubprocessProtocol` has different capabilities, thus requires specific adaptations.
|
|
13
|
-
* Check their documentations for details.
|
|
14
|
-
*
|
|
15
|
-
* The first protocol whose `isSupported` returns `true` will be used.
|
|
16
|
-
* If no `AdbSubprocessProtocol` is supported, an error will be thrown.
|
|
17
|
-
*
|
|
18
|
-
* @default [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol]
|
|
19
|
-
*/
|
|
20
|
-
protocols: AdbSubprocessProtocolConstructor[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const DEFAULT_OPTIONS: AdbSubprocessOptions = {
|
|
24
|
-
protocols: [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol],
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export interface AdbSubprocessWaitResult {
|
|
28
|
-
stdout: string;
|
|
29
|
-
stderr: string;
|
|
30
|
-
exitCode: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class AdbSubprocess {
|
|
34
|
-
public readonly adb: Adb;
|
|
35
|
-
|
|
36
|
-
public constructor(adb: Adb) {
|
|
37
|
-
this.adb = adb;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private async createProtocol(
|
|
41
|
-
mode: 'pty' | 'raw',
|
|
42
|
-
command?: string | string[],
|
|
43
|
-
options?: Partial<AdbSubprocessOptions>
|
|
44
|
-
): Promise<AdbSubprocessProtocol> {
|
|
45
|
-
const { protocols } = { ...DEFAULT_OPTIONS, ...options };
|
|
46
|
-
|
|
47
|
-
let Constructor: AdbSubprocessProtocolConstructor | undefined;
|
|
48
|
-
for (const item of protocols) {
|
|
49
|
-
// It's async so can't use `Array#find`
|
|
50
|
-
if (await item.isSupported(this.adb)) {
|
|
51
|
-
Constructor = item;
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (!Constructor) {
|
|
57
|
-
throw new Error('No specified protocol is supported by the device');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (Array.isArray(command)) {
|
|
61
|
-
command = command.join(' ');
|
|
62
|
-
} else if (command === undefined) {
|
|
63
|
-
// spawn the default shell
|
|
64
|
-
command = '';
|
|
65
|
-
}
|
|
66
|
-
return await Constructor[mode](this.adb, command);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Spawns an executable in PTY (interactive) mode.
|
|
71
|
-
* @param command The command to run. If omitted, the default shell will be spawned.
|
|
72
|
-
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
73
|
-
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
|
74
|
-
*/
|
|
75
|
-
public shell(
|
|
76
|
-
command?: string | string[],
|
|
77
|
-
options?: Partial<AdbSubprocessOptions>
|
|
78
|
-
): Promise<AdbSubprocessProtocol> {
|
|
79
|
-
return this.createProtocol('pty', command, options);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Spawns an executable and pipe the output.
|
|
84
|
-
* @param command The command to run, or an array of strings containing both command and args.
|
|
85
|
-
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
86
|
-
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
|
87
|
-
*/
|
|
88
|
-
public spawn(
|
|
89
|
-
command: string | string[],
|
|
90
|
-
options?: Partial<AdbSubprocessOptions>
|
|
91
|
-
): Promise<AdbSubprocessProtocol> {
|
|
92
|
-
return this.createProtocol('raw', command, options);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Spawns a new process, waits until it exits, and returns the entire output.
|
|
97
|
-
* @param command The command to run
|
|
98
|
-
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
99
|
-
* @returns The entire output of the command
|
|
100
|
-
*/
|
|
101
|
-
public async spawnAndWait(
|
|
102
|
-
command: string | string[],
|
|
103
|
-
options?: Partial<AdbSubprocessOptions>
|
|
104
|
-
): Promise<AdbSubprocessWaitResult> {
|
|
105
|
-
const shell = await this.spawn(command, options);
|
|
106
|
-
|
|
107
|
-
const stdout = new GatherStringStream();
|
|
108
|
-
const stderr = new GatherStringStream();
|
|
109
|
-
|
|
110
|
-
const [, , exitCode] = await Promise.all([
|
|
111
|
-
shell.stdout
|
|
112
|
-
.pipeThrough(new DecodeUtf8Stream())
|
|
113
|
-
.pipeTo(stdout),
|
|
114
|
-
shell.stderr
|
|
115
|
-
.pipeThrough(new DecodeUtf8Stream())
|
|
116
|
-
.pipeTo(stderr),
|
|
117
|
-
shell.exit
|
|
118
|
-
]);
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
stdout: stdout.result,
|
|
122
|
-
stderr: stderr.result,
|
|
123
|
-
exitCode,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Spawns a new process, waits until it exits, and returns the entire output.
|
|
129
|
-
* @param command The command to run
|
|
130
|
-
* @returns The entire output of the command
|
|
131
|
-
*/
|
|
132
|
-
public async spawnAndWaitLegacy(command: string | string[]): Promise<string> {
|
|
133
|
-
const { stdout } = await this.spawnAndWait(
|
|
134
|
-
command,
|
|
135
|
-
{ protocols: [AdbSubprocessNoneProtocol] }
|
|
136
|
-
);
|
|
137
|
-
return stdout;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
1
|
+
export * from './command.js';
|
|
2
|
+
export * from './protocols/index.js';
|
|
3
|
+
export * from './utils.js';
|