@yume-chan/adb 0.0.24 → 1.1.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 +42 -1
- package/README.md +4 -1
- package/esm/adb.d.ts +13 -7
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +3 -0
- 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/reverse.d.ts +12 -12
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +39 -30
- package/esm/commands/reverse.js.map +1 -1
- 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 +20 -12
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +16 -21
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +6 -6
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/list.d.ts +49 -27
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +9 -9
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +7 -6
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +3 -5
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +22 -16
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +12 -16
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.d.ts +19 -17
- package/esm/commands/sync/request.d.ts.map +1 -1
- package/esm/commands/sync/request.js +14 -18
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +18 -18
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +20 -19
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +1 -1
- package/esm/commands/sync/socket.js +2 -2
- package/esm/commands/sync/socket.js.map +1 -1
- package/esm/commands/sync/stat.d.ts +75 -51
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +73 -67
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +14 -14
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +4 -7
- 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 +8 -8
- 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 +7 -8
- package/esm/daemon/auth.js.map +1 -1
- package/esm/daemon/crypto.d.ts +1 -1
- package/esm/daemon/crypto.d.ts.map +1 -1
- package/esm/daemon/crypto.js +1 -0
- 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.js +6 -6
- package/esm/daemon/dispatcher.js.map +1 -1
- package/esm/daemon/packet.d.ts +46 -30
- package/esm/daemon/packet.d.ts.map +1 -1
- package/esm/daemon/packet.js +24 -21
- package/esm/daemon/packet.js.map +1 -1
- package/esm/daemon/socket.d.ts +1 -6
- package/esm/daemon/socket.d.ts.map +1 -1
- package/esm/daemon/socket.js +4 -27
- package/esm/daemon/socket.js.map +1 -1
- package/esm/daemon/transport.d.ts +14 -14
- package/esm/daemon/transport.d.ts.map +1 -1
- package/esm/daemon/transport.js +6 -8
- 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 +33 -35
- package/esm/server/client.d.ts.map +1 -1
- package/esm/server/client.js +136 -201
- package/esm/server/client.js.map +1 -1
- package/esm/server/index.d.ts +2 -0
- package/esm/server/index.d.ts.map +1 -1
- package/esm/server/index.js +2 -0
- package/esm/server/index.js.map +1 -1
- package/esm/server/observer.d.ts +8 -0
- package/esm/server/observer.d.ts.map +1 -0
- package/esm/server/observer.js +106 -0
- package/esm/server/observer.js.map +1 -0
- package/esm/server/stream.d.ts +19 -0
- package/esm/server/stream.d.ts.map +1 -0
- package/esm/server/stream.js +77 -0
- package/esm/server/stream.js.map +1 -0
- package/esm/server/transport.d.ts +3 -4
- package/esm/server/transport.d.ts.map +1 -1
- package/esm/server/transport.js +16 -16
- package/esm/server/transport.js.map +1 -1
- package/esm/utils/base64.d.ts.map +1 -1
- package/esm/utils/base64.js +19 -16
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/index.d.ts +1 -0
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +1 -0
- 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/ref.d.ts +18 -0
- package/esm/utils/ref.d.ts.map +1 -0
- package/esm/utils/ref.js +29 -0
- package/esm/utils/ref.js.map +1 -0
- package/package.json +13 -16
- package/src/adb.ts +13 -7
- package/src/banner.ts +8 -6
- package/src/commands/framebuffer.ts +44 -35
- package/src/commands/reverse.ts +49 -31
- package/src/commands/subprocess/protocols/none.ts +3 -5
- package/src/commands/subprocess/protocols/shell.ts +26 -24
- package/src/commands/subprocess/protocols/types.ts +6 -6
- package/src/commands/sync/list.ts +20 -13
- package/src/commands/sync/pull.ts +8 -7
- package/src/commands/sync/push.ts +20 -16
- package/src/commands/sync/request.ts +18 -19
- package/src/commands/sync/response.ts +28 -29
- package/src/commands/sync/socket.ts +2 -2
- package/src/commands/sync/stat.ts +93 -71
- package/src/commands/sync/sync.ts +4 -8
- package/src/commands/tcpip.ts +8 -8
- package/src/daemon/auth.ts +11 -9
- package/src/daemon/crypto.ts +2 -0
- package/src/daemon/device.ts +2 -2
- package/src/daemon/dispatcher.ts +6 -6
- package/src/daemon/packet.ts +37 -25
- package/src/daemon/socket.ts +4 -27
- package/src/daemon/transport.ts +36 -35
- package/src/device-observer.ts +10 -0
- package/src/features.ts +13 -11
- package/src/index.ts +1 -0
- package/src/server/client.ts +181 -242
- package/src/server/index.ts +2 -0
- package/src/server/observer.ts +144 -0
- package/src/server/stream.ts +100 -0
- package/src/server/transport.ts +18 -17
- package/src/utils/base64.ts +26 -18
- package/src/utils/index.ts +1 -0
- package/src/utils/no-op.ts +1 -0
- package/src/utils/ref.ts +37 -0
- package/tsconfig.build.json +1 -12
- package/tsconfig.build.tsbuildinfo +1 -1
- package/CHANGELOG.json +0 -298
package/src/server/client.ts
CHANGED
|
@@ -1,148 +1,110 @@
|
|
|
1
1
|
// cspell:ignore tport
|
|
2
2
|
|
|
3
|
+
import type { MaybePromiseLike } from "@yume-chan/async";
|
|
3
4
|
import { PromiseResolver } from "@yume-chan/async";
|
|
5
|
+
import type { Event } from "@yume-chan/event";
|
|
4
6
|
import { getUint64LittleEndian } from "@yume-chan/no-data-view";
|
|
5
7
|
import type {
|
|
6
8
|
AbortSignal,
|
|
7
|
-
ReadableWritablePair,
|
|
8
|
-
WritableStreamDefaultWriter,
|
|
9
|
-
} from "@yume-chan/stream-extra";
|
|
10
|
-
import {
|
|
11
|
-
BufferedReadableStream,
|
|
12
9
|
MaybeConsumable,
|
|
13
|
-
|
|
10
|
+
ReadableWritablePair,
|
|
14
11
|
} from "@yume-chan/stream-extra";
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
17
|
-
EMPTY_UINT8_ARRAY,
|
|
18
|
-
SyncPromise,
|
|
19
|
-
decodeUtf8,
|
|
20
|
-
encodeUtf8,
|
|
21
|
-
} from "@yume-chan/struct";
|
|
12
|
+
import { AbortController } from "@yume-chan/stream-extra";
|
|
22
13
|
|
|
23
14
|
import type { AdbIncomingSocketHandler, AdbSocket, Closeable } from "../adb.js";
|
|
24
15
|
import { AdbBanner } from "../banner.js";
|
|
16
|
+
import type { DeviceObserver as DeviceObserverBase } from "../device-observer.js";
|
|
25
17
|
import type { AdbFeature } from "../features.js";
|
|
26
|
-
import {
|
|
27
|
-
NOOP,
|
|
28
|
-
hexToNumber,
|
|
29
|
-
sequenceEqual,
|
|
30
|
-
write4HexDigits,
|
|
31
|
-
} from "../utils/index.js";
|
|
18
|
+
import { hexToNumber, sequenceEqual } from "../utils/index.js";
|
|
32
19
|
|
|
20
|
+
import { AdbServerDeviceObserverOwner } from "./observer.js";
|
|
21
|
+
import { AdbServerStream, FAIL } from "./stream.js";
|
|
33
22
|
import { AdbServerTransport } from "./transport.js";
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.#buffered = new BufferedReadableStream(connection.readable);
|
|
46
|
-
this.#writer = connection.writable.getWriter();
|
|
47
|
-
}
|
|
24
|
+
/**
|
|
25
|
+
* Client for the ADB Server.
|
|
26
|
+
*/
|
|
27
|
+
export class AdbServerClient {
|
|
28
|
+
static parseDeviceList(value: string): AdbServerClient.Device[] {
|
|
29
|
+
const devices: AdbServerClient.Device[] = [];
|
|
30
|
+
for (const line of value.split("\n")) {
|
|
31
|
+
if (!line) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
48
34
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
35
|
+
const parts = line.split(" ").filter(Boolean);
|
|
36
|
+
const serial = parts[0]!;
|
|
37
|
+
const status = parts[1]!;
|
|
38
|
+
if (status !== "device" && status !== "unauthorized") {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
52
41
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
42
|
+
let product: string | undefined;
|
|
43
|
+
let model: string | undefined;
|
|
44
|
+
let device: string | undefined;
|
|
45
|
+
let transportId: bigint | undefined;
|
|
46
|
+
for (let i = 2; i < parts.length; i += 1) {
|
|
47
|
+
const [key, value] = parts[i]!.split(":");
|
|
48
|
+
switch (key) {
|
|
49
|
+
case "product":
|
|
50
|
+
product = value;
|
|
51
|
+
break;
|
|
52
|
+
case "model":
|
|
53
|
+
model = value;
|
|
54
|
+
break;
|
|
55
|
+
case "device":
|
|
56
|
+
device = value;
|
|
57
|
+
break;
|
|
58
|
+
case "transport_id":
|
|
59
|
+
transportId = BigInt(value!);
|
|
60
|
+
break;
|
|
61
61
|
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// return result;
|
|
77
|
-
// ```
|
|
78
|
-
//
|
|
79
|
-
// Although, it will be super complex to use `SyncPromise` with async iterator,
|
|
80
|
-
// `stream.iterateExactly` need to return an
|
|
81
|
-
// `Iterator<Uint8Array | Promise<Uint8Array>>` instead of a true async iterator.
|
|
82
|
-
// Maybe `SyncPromise` should support async iterators directly.
|
|
83
|
-
return decodeUtf8(buffer);
|
|
84
|
-
})
|
|
85
|
-
.valueOrPromise();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async writeString(value: string): Promise<void> {
|
|
89
|
-
// TODO: investigate using `encodeUtf8("0000" + value)` then modifying the length
|
|
90
|
-
// That way allocates a new string (hopefully only a rope) instead of a new buffer
|
|
91
|
-
const encoded = encodeUtf8(value);
|
|
92
|
-
const buffer = new Uint8Array(4 + encoded.length);
|
|
93
|
-
write4HexDigits(buffer, 0, encoded.length);
|
|
94
|
-
buffer.set(encoded, 4);
|
|
95
|
-
await this.#writer.write(buffer);
|
|
62
|
+
}
|
|
63
|
+
if (!transportId) {
|
|
64
|
+
throw new Error(`No transport id for device ${serial}`);
|
|
65
|
+
}
|
|
66
|
+
devices.push({
|
|
67
|
+
serial,
|
|
68
|
+
authenticating: status === "unauthorized",
|
|
69
|
+
product,
|
|
70
|
+
model,
|
|
71
|
+
device,
|
|
72
|
+
transportId,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return devices;
|
|
96
76
|
}
|
|
97
77
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return;
|
|
78
|
+
static formatDeviceService(
|
|
79
|
+
device: AdbServerClient.DeviceSelector,
|
|
80
|
+
command: string,
|
|
81
|
+
) {
|
|
82
|
+
if (!device) {
|
|
83
|
+
return `host:${command}`;
|
|
105
84
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const reason = await this.readString();
|
|
109
|
-
throw new Error(reason);
|
|
85
|
+
if ("transportId" in device) {
|
|
86
|
+
return `host-transport-id:${device.transportId}:${command}`;
|
|
110
87
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
release() {
|
|
116
|
-
this.#writer.releaseLock();
|
|
117
|
-
return {
|
|
118
|
-
readable: this.#buffered.release(),
|
|
119
|
-
writable: this.#connection.writable,
|
|
120
|
-
closed: this.#connection.closed,
|
|
121
|
-
close: () => this.#connection.close(),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async dispose() {
|
|
126
|
-
await this.#buffered.cancel().catch(NOOP);
|
|
127
|
-
await this.#writer.close().catch(NOOP);
|
|
128
|
-
try {
|
|
129
|
-
await this.#connection.close();
|
|
130
|
-
} catch {
|
|
131
|
-
// ignore
|
|
88
|
+
if ("serial" in device) {
|
|
89
|
+
return `host-serial:${device.serial}:${command}`;
|
|
132
90
|
}
|
|
91
|
+
if ("usb" in device) {
|
|
92
|
+
return `host-usb:${command}`;
|
|
93
|
+
}
|
|
94
|
+
if ("tcp" in device) {
|
|
95
|
+
return `host-local:${command}`;
|
|
96
|
+
}
|
|
97
|
+
throw new TypeError("Invalid device selector");
|
|
133
98
|
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export class AdbServerClient {
|
|
137
|
-
static readonly VERSION = 41;
|
|
138
99
|
|
|
139
100
|
readonly connector: AdbServerClient.ServerConnector;
|
|
140
101
|
|
|
141
102
|
readonly wireless = new AdbServerClient.WirelessCommands(this);
|
|
142
103
|
readonly mDns = new AdbServerClient.MDnsCommands(this);
|
|
104
|
+
#observerOwner = new AdbServerDeviceObserverOwner(this);
|
|
143
105
|
|
|
144
|
-
constructor(
|
|
145
|
-
this.connector =
|
|
106
|
+
constructor(connector: AdbServerClient.ServerConnector) {
|
|
107
|
+
this.connector = connector;
|
|
146
108
|
}
|
|
147
109
|
|
|
148
110
|
async createConnection(
|
|
@@ -184,11 +146,11 @@ export class AdbServerClient {
|
|
|
184
146
|
}
|
|
185
147
|
}
|
|
186
148
|
|
|
187
|
-
async validateVersion() {
|
|
149
|
+
async validateVersion(minimalVersion: number) {
|
|
188
150
|
const version = await this.getVersion();
|
|
189
|
-
if (version
|
|
151
|
+
if (version < minimalVersion) {
|
|
190
152
|
throw new Error(
|
|
191
|
-
`adb server version (${version}) doesn't match this client (${
|
|
153
|
+
`adb server version (${version}) doesn't match this client (${minimalVersion})`,
|
|
192
154
|
);
|
|
193
155
|
}
|
|
194
156
|
}
|
|
@@ -214,118 +176,28 @@ export class AdbServerClient {
|
|
|
214
176
|
}
|
|
215
177
|
}
|
|
216
178
|
|
|
217
|
-
parseDeviceList(value: string): AdbServerClient.Device[] {
|
|
218
|
-
const devices: AdbServerClient.Device[] = [];
|
|
219
|
-
for (const line of value.split("\n")) {
|
|
220
|
-
if (!line) {
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const parts = line.split(" ").filter(Boolean);
|
|
225
|
-
const serial = parts[0]!;
|
|
226
|
-
const status = parts[1]!;
|
|
227
|
-
if (status !== "device" && status !== "unauthorized") {
|
|
228
|
-
continue;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
let product: string | undefined;
|
|
232
|
-
let model: string | undefined;
|
|
233
|
-
let device: string | undefined;
|
|
234
|
-
let transportId: bigint | undefined;
|
|
235
|
-
for (let i = 2; i < parts.length; i += 1) {
|
|
236
|
-
const [key, value] = parts[i]!.split(":");
|
|
237
|
-
switch (key) {
|
|
238
|
-
case "product":
|
|
239
|
-
product = value;
|
|
240
|
-
break;
|
|
241
|
-
case "model":
|
|
242
|
-
model = value;
|
|
243
|
-
break;
|
|
244
|
-
case "device":
|
|
245
|
-
device = value;
|
|
246
|
-
break;
|
|
247
|
-
case "transport_id":
|
|
248
|
-
transportId = BigInt(value!);
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
if (!transportId) {
|
|
253
|
-
throw new Error(`No transport id for device ${serial}`);
|
|
254
|
-
}
|
|
255
|
-
devices.push({
|
|
256
|
-
serial,
|
|
257
|
-
authenticating: status === "unauthorized",
|
|
258
|
-
product,
|
|
259
|
-
model,
|
|
260
|
-
device,
|
|
261
|
-
transportId,
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
return devices;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
179
|
/**
|
|
268
|
-
*
|
|
180
|
+
* Get a list of connected devices from ADB Server.
|
|
181
|
+
*
|
|
182
|
+
* Equivalent ADB Command: `adb devices -l`
|
|
269
183
|
*/
|
|
270
184
|
async getDevices(): Promise<AdbServerClient.Device[]> {
|
|
271
185
|
const connection = await this.createConnection("host:devices-l");
|
|
272
186
|
try {
|
|
273
187
|
const response = await connection.readString();
|
|
274
|
-
return
|
|
188
|
+
return AdbServerClient.parseDeviceList(response);
|
|
275
189
|
} finally {
|
|
276
190
|
await connection.dispose();
|
|
277
191
|
}
|
|
278
192
|
}
|
|
279
193
|
|
|
280
194
|
/**
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
* @param signal An optional `AbortSignal` to stop tracking
|
|
284
|
-
*
|
|
285
|
-
* When `signal` is aborted, `trackDevices` will return normally, instead of throwing `signal.reason`.
|
|
195
|
+
* Monitors device list changes.
|
|
286
196
|
*/
|
|
287
|
-
async
|
|
288
|
-
|
|
289
|
-
):
|
|
290
|
-
|
|
291
|
-
try {
|
|
292
|
-
while (true) {
|
|
293
|
-
const response = await raceSignal(
|
|
294
|
-
async () => await connection.readString(),
|
|
295
|
-
signal,
|
|
296
|
-
);
|
|
297
|
-
const devices = this.parseDeviceList(response);
|
|
298
|
-
yield devices;
|
|
299
|
-
}
|
|
300
|
-
} catch (e) {
|
|
301
|
-
if (e === signal?.reason) {
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
} finally {
|
|
305
|
-
await connection.dispose();
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
formatDeviceService(
|
|
310
|
-
device: AdbServerClient.DeviceSelector,
|
|
311
|
-
command: string,
|
|
312
|
-
) {
|
|
313
|
-
if (!device) {
|
|
314
|
-
return `host:${command}`;
|
|
315
|
-
}
|
|
316
|
-
if ("transportId" in device) {
|
|
317
|
-
return `host-transport-id:${device.transportId}:${command}`;
|
|
318
|
-
}
|
|
319
|
-
if ("serial" in device) {
|
|
320
|
-
return `host-serial:${device.serial}:${command}`;
|
|
321
|
-
}
|
|
322
|
-
if ("usb" in device) {
|
|
323
|
-
return `host-usb:${command}`;
|
|
324
|
-
}
|
|
325
|
-
if ("tcp" in device) {
|
|
326
|
-
return `host-local:${command}`;
|
|
327
|
-
}
|
|
328
|
-
throw new TypeError("Invalid device selector");
|
|
197
|
+
async trackDevices(
|
|
198
|
+
options?: AdbServerClient.ServerConnectionOptions,
|
|
199
|
+
): Promise<AdbServerClient.DeviceObserver> {
|
|
200
|
+
return this.#observerOwner.createObserver(options);
|
|
329
201
|
}
|
|
330
202
|
|
|
331
203
|
/**
|
|
@@ -335,7 +207,7 @@ export class AdbServerClient {
|
|
|
335
207
|
const connection = await this.createConnection(
|
|
336
208
|
device === "offline"
|
|
337
209
|
? "host:reconnect-offline"
|
|
338
|
-
:
|
|
210
|
+
: AdbServerClient.formatDeviceService(device, "reconnect"),
|
|
339
211
|
);
|
|
340
212
|
try {
|
|
341
213
|
await connection.readString();
|
|
@@ -395,20 +267,22 @@ export class AdbServerClient {
|
|
|
395
267
|
device: AdbServerClient.DeviceSelector,
|
|
396
268
|
service: string,
|
|
397
269
|
): Promise<AdbServerClient.Socket> {
|
|
398
|
-
await this.validateVersion();
|
|
399
|
-
|
|
400
270
|
let switchService: string;
|
|
401
271
|
let transportId: bigint | undefined;
|
|
402
272
|
if (!device) {
|
|
273
|
+
await this.validateVersion(41);
|
|
403
274
|
switchService = `host:tport:any`;
|
|
404
275
|
} else if ("transportId" in device) {
|
|
405
276
|
switchService = `host:transport-id:${device.transportId}`;
|
|
406
277
|
transportId = device.transportId;
|
|
407
278
|
} else if ("serial" in device) {
|
|
279
|
+
await this.validateVersion(41);
|
|
408
280
|
switchService = `host:tport:serial:${device.serial}`;
|
|
409
281
|
} else if ("usb" in device) {
|
|
282
|
+
await this.validateVersion(41);
|
|
410
283
|
switchService = `host:tport:usb`;
|
|
411
284
|
} else if ("tcp" in device) {
|
|
285
|
+
await this.validateVersion(41);
|
|
412
286
|
switchService = `host:tport:local`;
|
|
413
287
|
} else {
|
|
414
288
|
throw new TypeError("Invalid device selector");
|
|
@@ -437,9 +311,7 @@ export class AdbServerClient {
|
|
|
437
311
|
transportId,
|
|
438
312
|
service,
|
|
439
313
|
readable: socket.readable,
|
|
440
|
-
writable:
|
|
441
|
-
socket.writable,
|
|
442
|
-
).bePipedThroughFrom(new MaybeConsumable.UnwrapStream()),
|
|
314
|
+
writable: socket.writable,
|
|
443
315
|
get closed() {
|
|
444
316
|
return socket.closed;
|
|
445
317
|
},
|
|
@@ -452,18 +324,7 @@ export class AdbServerClient {
|
|
|
452
324
|
throw e;
|
|
453
325
|
}
|
|
454
326
|
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Wait for a device to be connected or disconnected.
|
|
458
|
-
*
|
|
459
|
-
* `adb wait-for-<state>`
|
|
460
|
-
*
|
|
461
|
-
* @param device The device selector
|
|
462
|
-
* @param state The state to wait for
|
|
463
|
-
* @param options The options
|
|
464
|
-
* @returns A promise that resolves when the condition is met.
|
|
465
|
-
*/
|
|
466
|
-
async waitFor(
|
|
327
|
+
async #waitForUnchecked(
|
|
467
328
|
device: AdbServerClient.DeviceSelector,
|
|
468
329
|
state: "device" | "disconnect",
|
|
469
330
|
options?: AdbServerClient.ServerConnectionOptions,
|
|
@@ -485,7 +346,7 @@ export class AdbServerClient {
|
|
|
485
346
|
|
|
486
347
|
// `waitFor` can't use `connectDevice`, because the device
|
|
487
348
|
// might not be available yet.
|
|
488
|
-
const service =
|
|
349
|
+
const service = AdbServerClient.formatDeviceService(
|
|
489
350
|
device,
|
|
490
351
|
`wait-for-${type}-${state}`,
|
|
491
352
|
);
|
|
@@ -498,6 +359,63 @@ export class AdbServerClient {
|
|
|
498
359
|
}
|
|
499
360
|
}
|
|
500
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Wait for a device to be connected or disconnected.
|
|
364
|
+
*
|
|
365
|
+
* `adb wait-for-<state>`
|
|
366
|
+
*
|
|
367
|
+
* @param device The device selector
|
|
368
|
+
* @param state The state to wait for
|
|
369
|
+
* @param options The options
|
|
370
|
+
* @returns A promise that resolves when the condition is met.
|
|
371
|
+
*/
|
|
372
|
+
async waitFor(
|
|
373
|
+
device: AdbServerClient.DeviceSelector,
|
|
374
|
+
state: "device" | "disconnect",
|
|
375
|
+
options?: AdbServerClient.ServerConnectionOptions,
|
|
376
|
+
): Promise<void> {
|
|
377
|
+
if (state === "disconnect") {
|
|
378
|
+
await this.validateVersion(41);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return this.#waitForUnchecked(device, state, options);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
async waitForDisconnect(
|
|
385
|
+
transportId: bigint,
|
|
386
|
+
options?: AdbServerClient.ServerConnectionOptions,
|
|
387
|
+
): Promise<void> {
|
|
388
|
+
const serverVersion = await this.getVersion();
|
|
389
|
+
if (serverVersion >= 41) {
|
|
390
|
+
return this.#waitForUnchecked(
|
|
391
|
+
{ transportId },
|
|
392
|
+
"disconnect",
|
|
393
|
+
options,
|
|
394
|
+
);
|
|
395
|
+
} else {
|
|
396
|
+
const observer = await this.trackDevices(options);
|
|
397
|
+
return new Promise<void>((resolve, reject) => {
|
|
398
|
+
observer.onDeviceRemove((devices) => {
|
|
399
|
+
if (
|
|
400
|
+
devices.some(
|
|
401
|
+
(device) => device.transportId === transportId,
|
|
402
|
+
)
|
|
403
|
+
) {
|
|
404
|
+
observer.stop();
|
|
405
|
+
resolve();
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
observer.onError((e) => {
|
|
409
|
+
observer.stop();
|
|
410
|
+
reject(e);
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Creates an ADB Transport for the specified device.
|
|
418
|
+
*/
|
|
501
419
|
async createTransport(
|
|
502
420
|
device: AdbServerClient.DeviceSelector,
|
|
503
421
|
): Promise<AdbServerTransport> {
|
|
@@ -515,12 +433,26 @@ export class AdbServerClient {
|
|
|
515
433
|
features,
|
|
516
434
|
);
|
|
517
435
|
|
|
518
|
-
|
|
436
|
+
const waitAbortController = new AbortController();
|
|
437
|
+
const disconnected = this.waitForDisconnect(transportId, {
|
|
438
|
+
unref: true,
|
|
439
|
+
signal: waitAbortController.signal,
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
const transport = new AdbServerTransport(
|
|
519
443
|
this,
|
|
520
444
|
info?.serial ?? "",
|
|
521
445
|
banner,
|
|
522
446
|
transportId,
|
|
447
|
+
disconnected,
|
|
523
448
|
);
|
|
449
|
+
|
|
450
|
+
transport.disconnected.then(
|
|
451
|
+
() => waitAbortController.abort(),
|
|
452
|
+
() => waitAbortController.abort(),
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
return transport;
|
|
524
456
|
}
|
|
525
457
|
}
|
|
526
458
|
|
|
@@ -562,7 +494,7 @@ export namespace AdbServerClient {
|
|
|
562
494
|
}
|
|
563
495
|
|
|
564
496
|
export interface ServerConnection
|
|
565
|
-
extends ReadableWritablePair<Uint8Array, Uint8Array
|
|
497
|
+
extends ReadableWritablePair<Uint8Array, MaybeConsumable<Uint8Array>>,
|
|
566
498
|
Closeable {
|
|
567
499
|
get closed(): Promise<void>;
|
|
568
500
|
}
|
|
@@ -570,22 +502,25 @@ export namespace AdbServerClient {
|
|
|
570
502
|
export interface ServerConnector {
|
|
571
503
|
connect(
|
|
572
504
|
options?: ServerConnectionOptions,
|
|
573
|
-
):
|
|
505
|
+
): MaybePromiseLike<ServerConnection>;
|
|
574
506
|
|
|
575
507
|
addReverseTunnel(
|
|
576
508
|
handler: AdbIncomingSocketHandler,
|
|
577
509
|
address?: string,
|
|
578
|
-
):
|
|
510
|
+
): MaybePromiseLike<string>;
|
|
579
511
|
|
|
580
|
-
removeReverseTunnel(address: string):
|
|
512
|
+
removeReverseTunnel(address: string): MaybePromiseLike<void>;
|
|
581
513
|
|
|
582
|
-
clearReverseTunnels():
|
|
514
|
+
clearReverseTunnels(): MaybePromiseLike<void>;
|
|
583
515
|
}
|
|
584
516
|
|
|
585
517
|
export interface Socket extends AdbSocket {
|
|
586
518
|
transportId: bigint;
|
|
587
519
|
}
|
|
588
520
|
|
|
521
|
+
/**
|
|
522
|
+
* A union type for selecting a device.
|
|
523
|
+
*/
|
|
589
524
|
export type DeviceSelector =
|
|
590
525
|
| { transportId: bigint }
|
|
591
526
|
| { serial: string }
|
|
@@ -732,4 +667,8 @@ export namespace AdbServerClient {
|
|
|
732
667
|
}
|
|
733
668
|
}
|
|
734
669
|
}
|
|
670
|
+
|
|
671
|
+
export interface DeviceObserver extends DeviceObserverBase<Device> {
|
|
672
|
+
onError: Event<Error>;
|
|
673
|
+
}
|
|
735
674
|
}
|
package/src/server/index.ts
CHANGED