@yume-chan/adb 0.0.21 → 0.0.22
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 +21 -0
- package/CHANGELOG.md +11 -1
- package/README.md +46 -366
- package/esm/adb.d.ts +5 -4
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js.map +1 -1
- package/esm/banner.js.map +1 -1
- package/esm/commands/framebuffer.d.ts +1 -1
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js.map +1 -1
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.js.map +1 -1
- package/esm/commands/subprocess/protocols/none.d.ts +2 -1
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js +11 -14
- 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 +6 -2
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/utils.js.map +1 -1
- package/esm/commands/sync/list.d.ts +2 -1
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +2 -2
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +4 -0
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +1 -1
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +1 -1
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +1 -0
- package/esm/commands/sync/socket.d.ts.map +1 -1
- package/esm/commands/sync/socket.js +4 -0
- package/esm/commands/sync/socket.js.map +1 -1
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts +21 -0
- package/esm/commands/tcpip.d.ts.map +1 -1
- package/esm/commands/tcpip.js +18 -0
- package/esm/commands/tcpip.js.map +1 -1
- package/esm/daemon/auth.js.map +1 -1
- package/esm/daemon/crypto.js.map +1 -1
- package/esm/daemon/dispatcher.d.ts +2 -1
- package/esm/daemon/dispatcher.d.ts.map +1 -1
- package/esm/daemon/dispatcher.js +56 -45
- package/esm/daemon/dispatcher.js.map +1 -1
- package/esm/daemon/packet.d.ts +5 -5
- package/esm/daemon/packet.d.ts.map +1 -1
- package/esm/daemon/packet.js +1 -1
- package/esm/daemon/packet.js.map +1 -1
- package/esm/daemon/socket.d.ts +7 -12
- package/esm/daemon/socket.d.ts.map +1 -1
- package/esm/daemon/socket.js +49 -41
- package/esm/daemon/socket.js.map +1 -1
- package/esm/daemon/transport.d.ts +8 -4
- package/esm/daemon/transport.d.ts.map +1 -1
- package/esm/daemon/transport.js +10 -8
- package/esm/daemon/transport.js.map +1 -1
- package/esm/server/client.d.ts +12 -8
- package/esm/server/client.d.ts.map +1 -1
- package/esm/server/client.js +40 -20
- package/esm/server/client.js.map +1 -1
- package/esm/utils/auto-reset-event.js.map +1 -1
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/conditional-variable.js.map +1 -1
- package/esm/utils/hex.js.map +1 -1
- package/package.json +12 -12
- package/src/adb.ts +7 -5
- package/src/commands/framebuffer.ts +1 -1
- package/src/commands/subprocess/protocols/none.ts +15 -19
- package/src/commands/subprocess/protocols/shell.ts +7 -2
- package/src/commands/sync/list.ts +6 -2
- package/src/commands/sync/pull.ts +3 -0
- package/src/commands/sync/response.ts +2 -2
- package/src/commands/sync/socket.ts +5 -0
- package/src/commands/tcpip.ts +44 -0
- package/src/daemon/dispatcher.ts +73 -58
- package/src/daemon/packet.ts +1 -1
- package/src/daemon/socket.ts +71 -84
- package/src/daemon/transport.ts +22 -14
- package/src/server/client.ts +54 -40
- package/tsconfig.build.tsbuildinfo +1 -1
package/src/daemon/dispatcher.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AsyncOperationManager,
|
|
3
|
+
PromiseResolver,
|
|
4
|
+
delay,
|
|
5
|
+
} from "@yume-chan/async";
|
|
2
6
|
import type {
|
|
3
7
|
Consumable,
|
|
4
8
|
ReadableWritablePair,
|
|
@@ -12,7 +16,7 @@ import {
|
|
|
12
16
|
import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct";
|
|
13
17
|
|
|
14
18
|
import type { AdbIncomingSocketHandler, AdbSocket, Closeable } from "../adb.js";
|
|
15
|
-
import { decodeUtf8, encodeUtf8
|
|
19
|
+
import { decodeUtf8, encodeUtf8 } from "../utils/index.js";
|
|
16
20
|
|
|
17
21
|
import type { AdbPacketData, AdbPacketInit } from "./packet.js";
|
|
18
22
|
import { AdbCommand, calculateChecksum } from "./packet.js";
|
|
@@ -32,6 +36,7 @@ export interface AdbPacketDispatcherOptions {
|
|
|
32
36
|
* Whether to preserve the connection open after the `AdbPacketDispatcher` is closed.
|
|
33
37
|
*/
|
|
34
38
|
preserveConnection?: boolean | undefined;
|
|
39
|
+
debugSlowRead?: boolean | undefined;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
/**
|
|
@@ -80,30 +85,18 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
80
85
|
new WritableStream({
|
|
81
86
|
write: async (packet) => {
|
|
82
87
|
switch (packet.command) {
|
|
83
|
-
case AdbCommand.OK:
|
|
84
|
-
this.#handleOk(packet);
|
|
85
|
-
break;
|
|
86
88
|
case AdbCommand.Close:
|
|
87
89
|
await this.#handleClose(packet);
|
|
88
90
|
break;
|
|
89
|
-
case AdbCommand.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
.get(packet.arg1)!
|
|
93
|
-
.enqueue(packet.payload);
|
|
94
|
-
await this.sendPacket(
|
|
95
|
-
AdbCommand.OK,
|
|
96
|
-
packet.arg1,
|
|
97
|
-
packet.arg0,
|
|
98
|
-
);
|
|
99
|
-
break;
|
|
100
|
-
}
|
|
101
|
-
throw new Error(
|
|
102
|
-
`Unknown local socket id: ${packet.arg1}`,
|
|
103
|
-
);
|
|
91
|
+
case AdbCommand.Okay:
|
|
92
|
+
this.#handleOkay(packet);
|
|
93
|
+
break;
|
|
104
94
|
case AdbCommand.Open:
|
|
105
95
|
await this.#handleOpen(packet);
|
|
106
96
|
break;
|
|
97
|
+
case AdbCommand.Write:
|
|
98
|
+
await this.#handleWrite(packet);
|
|
99
|
+
break;
|
|
107
100
|
default:
|
|
108
101
|
// Junk data may only appear in the authentication phase,
|
|
109
102
|
// since the dispatcher only works after authentication,
|
|
@@ -137,24 +130,6 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
137
130
|
this.#writer = connection.writable.getWriter();
|
|
138
131
|
}
|
|
139
132
|
|
|
140
|
-
#handleOk(packet: AdbPacketData) {
|
|
141
|
-
if (this.#initializers.resolve(packet.arg1, packet.arg0)) {
|
|
142
|
-
// Device successfully created the socket
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const socket = this.#sockets.get(packet.arg1);
|
|
147
|
-
if (socket) {
|
|
148
|
-
// Device has received last `WRTE` to the socket
|
|
149
|
-
socket.ack();
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Maybe the device is responding to a packet of last connection
|
|
154
|
-
// Tell the device to close the socket
|
|
155
|
-
void this.sendPacket(AdbCommand.Close, packet.arg1, packet.arg0);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
133
|
async #handleClose(packet: AdbPacketData) {
|
|
159
134
|
// If the socket is still pending
|
|
160
135
|
if (
|
|
@@ -182,15 +157,8 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
182
157
|
// Ignore `arg0` and search for the socket
|
|
183
158
|
const socket = this.#sockets.get(packet.arg1);
|
|
184
159
|
if (socket) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
await this.sendPacket(
|
|
188
|
-
AdbCommand.Close,
|
|
189
|
-
packet.arg1,
|
|
190
|
-
packet.arg0,
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
await socket.dispose();
|
|
160
|
+
await socket.close();
|
|
161
|
+
socket.dispose();
|
|
194
162
|
this.#sockets.delete(packet.arg1);
|
|
195
163
|
return;
|
|
196
164
|
}
|
|
@@ -200,16 +168,22 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
200
168
|
// the device may also respond with two `CLSE` packets.
|
|
201
169
|
}
|
|
202
170
|
|
|
203
|
-
|
|
204
|
-
this.#
|
|
205
|
-
|
|
171
|
+
#handleOkay(packet: AdbPacketData) {
|
|
172
|
+
if (this.#initializers.resolve(packet.arg1, packet.arg0)) {
|
|
173
|
+
// Device successfully created the socket
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
206
176
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
177
|
+
const socket = this.#sockets.get(packet.arg1);
|
|
178
|
+
if (socket) {
|
|
179
|
+
// Device has received last `WRTE` to the socket
|
|
180
|
+
socket.ack();
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
210
183
|
|
|
211
|
-
|
|
212
|
-
|
|
184
|
+
// Maybe the device is responding to a packet of last connection
|
|
185
|
+
// Tell the device to close the socket
|
|
186
|
+
void this.sendPacket(AdbCommand.Close, packet.arg1, packet.arg0);
|
|
213
187
|
}
|
|
214
188
|
|
|
215
189
|
async #handleOpen(packet: AdbPacketData) {
|
|
@@ -241,12 +215,41 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
241
215
|
try {
|
|
242
216
|
await handler(controller.socket);
|
|
243
217
|
this.#sockets.set(localId, controller);
|
|
244
|
-
await this.sendPacket(AdbCommand.
|
|
218
|
+
await this.sendPacket(AdbCommand.Okay, localId, remoteId);
|
|
245
219
|
} catch (e) {
|
|
246
220
|
await this.sendPacket(AdbCommand.Close, 0, remoteId);
|
|
247
221
|
}
|
|
248
222
|
}
|
|
249
223
|
|
|
224
|
+
async #handleWrite(packet: AdbPacketData) {
|
|
225
|
+
const socket = this.#sockets.get(packet.arg1);
|
|
226
|
+
if (!socket) {
|
|
227
|
+
throw new Error(`Unknown local socket id: ${packet.arg1}`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
let handled = false;
|
|
231
|
+
await Promise.race([
|
|
232
|
+
delay(5000).then(() => {
|
|
233
|
+
if (this.options.debugSlowRead && !handled) {
|
|
234
|
+
throw new Error(
|
|
235
|
+
`packet for \`${socket.service}\` not handled in 5 seconds`,
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}),
|
|
239
|
+
(async () => {
|
|
240
|
+
await socket.enqueue(packet.payload);
|
|
241
|
+
await this.sendPacket(
|
|
242
|
+
AdbCommand.Okay,
|
|
243
|
+
packet.arg1,
|
|
244
|
+
packet.arg0,
|
|
245
|
+
);
|
|
246
|
+
handled = true;
|
|
247
|
+
})(),
|
|
248
|
+
]);
|
|
249
|
+
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
250
253
|
async createSocket(service: string): Promise<AdbSocket> {
|
|
251
254
|
if (this.options.appendNullToServiceString) {
|
|
252
255
|
service += "\0";
|
|
@@ -269,6 +272,18 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
269
272
|
return controller.socket;
|
|
270
273
|
}
|
|
271
274
|
|
|
275
|
+
addReverseTunnel(service: string, handler: AdbIncomingSocketHandler) {
|
|
276
|
+
this.#incomingSocketHandlers.set(service, handler);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
removeReverseTunnel(address: string) {
|
|
280
|
+
this.#incomingSocketHandlers.delete(address);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
clearReverseTunnels() {
|
|
284
|
+
this.#incomingSocketHandlers.clear();
|
|
285
|
+
}
|
|
286
|
+
|
|
272
287
|
async sendPacket(
|
|
273
288
|
command: AdbCommand,
|
|
274
289
|
arg0: number,
|
|
@@ -307,7 +322,7 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
307
322
|
this.#closed = true;
|
|
308
323
|
|
|
309
324
|
this.#readAbortController.abort();
|
|
310
|
-
if (this.options.preserveConnection
|
|
325
|
+
if (this.options.preserveConnection) {
|
|
311
326
|
this.#writer.releaseLock();
|
|
312
327
|
} else {
|
|
313
328
|
await this.#writer.close();
|
|
@@ -318,7 +333,7 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
318
333
|
|
|
319
334
|
#dispose() {
|
|
320
335
|
for (const socket of this.#sockets.values()) {
|
|
321
|
-
socket.dispose()
|
|
336
|
+
socket.dispose();
|
|
322
337
|
}
|
|
323
338
|
|
|
324
339
|
this.#disconnected.resolve();
|
package/src/daemon/packet.ts
CHANGED
package/src/daemon/socket.ts
CHANGED
|
@@ -4,18 +4,16 @@ import type {
|
|
|
4
4
|
Consumable,
|
|
5
5
|
PushReadableStreamController,
|
|
6
6
|
ReadableStream,
|
|
7
|
-
ReadableWritablePair,
|
|
8
7
|
WritableStream,
|
|
8
|
+
WritableStreamDefaultController,
|
|
9
9
|
} from "@yume-chan/stream-extra";
|
|
10
10
|
import {
|
|
11
11
|
ConsumableWritableStream,
|
|
12
|
-
DistributionStream,
|
|
13
|
-
DuplexStreamFactory,
|
|
14
12
|
PushReadableStream,
|
|
15
|
-
pipeFrom,
|
|
16
13
|
} from "@yume-chan/stream-extra";
|
|
17
14
|
|
|
18
|
-
import type {
|
|
15
|
+
import type { AdbSocket } from "../adb.js";
|
|
16
|
+
import { raceSignal } from "../server/index.js";
|
|
19
17
|
|
|
20
18
|
import type { AdbPacketDispatcher } from "./dispatcher.js";
|
|
21
19
|
import { AdbCommand } from "./packet.js";
|
|
@@ -36,11 +34,7 @@ export interface AdbDaemonSocketConstructionOptions
|
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
export class AdbDaemonSocketController
|
|
39
|
-
implements
|
|
40
|
-
AdbDaemonSocketInfo,
|
|
41
|
-
ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>,
|
|
42
|
-
Closeable,
|
|
43
|
-
Disposable
|
|
37
|
+
implements AdbDaemonSocketInfo, AdbSocket, Disposable
|
|
44
38
|
{
|
|
45
39
|
readonly #dispatcher!: AdbPacketDispatcher;
|
|
46
40
|
|
|
@@ -49,8 +43,6 @@ export class AdbDaemonSocketController
|
|
|
49
43
|
readonly localCreated!: boolean;
|
|
50
44
|
readonly service!: string;
|
|
51
45
|
|
|
52
|
-
#duplex: DuplexStreamFactory<Uint8Array, Consumable<Uint8Array>>;
|
|
53
|
-
|
|
54
46
|
#readable: ReadableStream<Uint8Array>;
|
|
55
47
|
#readableController!: PushReadableStreamController<Uint8Array>;
|
|
56
48
|
get readable() {
|
|
@@ -58,16 +50,14 @@ export class AdbDaemonSocketController
|
|
|
58
50
|
}
|
|
59
51
|
|
|
60
52
|
#writePromise: PromiseResolver<void> | undefined;
|
|
53
|
+
#writableController!: WritableStreamDefaultController;
|
|
61
54
|
readonly writable: WritableStream<Consumable<Uint8Array>>;
|
|
62
55
|
|
|
63
56
|
#closed = false;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
*
|
|
67
|
-
* It's only used by dispatcher to avoid sending another `CLSE` packet to remote.
|
|
68
|
-
*/
|
|
57
|
+
|
|
58
|
+
#closedPromise = new PromiseResolver<void>();
|
|
69
59
|
get closed() {
|
|
70
|
-
return this.#
|
|
60
|
+
return this.#closedPromise.promise;
|
|
71
61
|
}
|
|
72
62
|
|
|
73
63
|
#socket: AdbDaemonSocket;
|
|
@@ -82,76 +72,56 @@ export class AdbDaemonSocketController
|
|
|
82
72
|
this.localCreated = options.localCreated;
|
|
83
73
|
this.service = options.service;
|
|
84
74
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// https://www.plantuml.com/plantuml/png/TL0zoeGm4ErpYc3l5JxyS0yWM6mX5j4C6p4cxcJ25ejttuGX88ZftizxUKmJI275pGhXl0PP_UkfK_CAz5Z2hcWsW9Ny2fdU4C1f5aSchFVxA8vJjlTPRhqZzDQMRB7AklwJ0xXtX0ZSKH1h24ghoKAdGY23FhxC4nS2pDvxzIvxb-8THU0XlEQJ-ZB7SnXTAvc_LhOckhMdLBnbtndpb-SB7a8q2SRD_W00
|
|
88
|
-
|
|
89
|
-
this.#duplex = new DuplexStreamFactory<
|
|
90
|
-
Uint8Array,
|
|
91
|
-
Consumable<Uint8Array>
|
|
92
|
-
>({
|
|
93
|
-
close: async () => {
|
|
94
|
-
this.#closed = true;
|
|
95
|
-
|
|
96
|
-
await this.#dispatcher.sendPacket(
|
|
97
|
-
AdbCommand.Close,
|
|
98
|
-
this.localId,
|
|
99
|
-
this.remoteId
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
// Don't `dispose` here, we need to wait for `CLSE` response packet.
|
|
103
|
-
return false;
|
|
104
|
-
},
|
|
105
|
-
dispose: () => {
|
|
106
|
-
// Error out the pending writes
|
|
107
|
-
this.#writePromise?.reject(new Error("Socket closed"));
|
|
108
|
-
},
|
|
75
|
+
this.#readable = new PushReadableStream((controller) => {
|
|
76
|
+
this.#readableController = controller;
|
|
109
77
|
});
|
|
110
78
|
|
|
111
|
-
this
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
79
|
+
this.writable = new ConsumableWritableStream<Uint8Array>({
|
|
80
|
+
start: (controller) => {
|
|
81
|
+
this.#writableController = controller;
|
|
82
|
+
},
|
|
83
|
+
write: async (data, controller) => {
|
|
84
|
+
const size = data.length;
|
|
85
|
+
const chunkSize = this.#dispatcher.options.maxPayloadSize;
|
|
86
|
+
for (
|
|
87
|
+
let start = 0, end = chunkSize;
|
|
88
|
+
start < size;
|
|
89
|
+
start = end, end += chunkSize
|
|
90
|
+
) {
|
|
91
|
+
this.#writePromise = new PromiseResolver();
|
|
92
|
+
await this.#dispatcher.sendPacket(
|
|
93
|
+
AdbCommand.Write,
|
|
94
|
+
this.localId,
|
|
95
|
+
this.remoteId,
|
|
96
|
+
data.subarray(start, end),
|
|
97
|
+
);
|
|
98
|
+
// Wait for ack packet
|
|
99
|
+
await raceSignal(
|
|
100
|
+
() => this.#writePromise!.promise,
|
|
101
|
+
controller.signal,
|
|
102
|
+
);
|
|
121
103
|
}
|
|
122
|
-
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
this.writable = pipeFrom(
|
|
126
|
-
this.#duplex.createWritable(
|
|
127
|
-
new ConsumableWritableStream<Uint8Array>({
|
|
128
|
-
write: async (chunk) => {
|
|
129
|
-
// Wait for an ack packet
|
|
130
|
-
this.#writePromise = new PromiseResolver();
|
|
131
|
-
await this.#dispatcher.sendPacket(
|
|
132
|
-
AdbCommand.Write,
|
|
133
|
-
this.localId,
|
|
134
|
-
this.remoteId,
|
|
135
|
-
chunk
|
|
136
|
-
);
|
|
137
|
-
await this.#writePromise.promise;
|
|
138
|
-
},
|
|
139
|
-
})
|
|
140
|
-
),
|
|
141
|
-
new DistributionStream(this.#dispatcher.options.maxPayloadSize)
|
|
142
|
-
);
|
|
104
|
+
},
|
|
105
|
+
});
|
|
143
106
|
|
|
144
107
|
this.#socket = new AdbDaemonSocket(this);
|
|
145
108
|
}
|
|
146
109
|
|
|
147
110
|
async enqueue(data: Uint8Array) {
|
|
148
|
-
//
|
|
149
|
-
//
|
|
111
|
+
// Consumers can `cancel` the `readable` if they are not interested in future data.
|
|
112
|
+
// Throw away the data if that happens.
|
|
150
113
|
if (this.#readableController.abortSignal.aborted) {
|
|
151
114
|
return;
|
|
152
115
|
}
|
|
153
116
|
|
|
154
|
-
|
|
117
|
+
try {
|
|
118
|
+
await this.#readableController.enqueue(data);
|
|
119
|
+
} catch (e) {
|
|
120
|
+
if (this.#readableController.abortSignal.aborted) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
throw e;
|
|
124
|
+
}
|
|
155
125
|
}
|
|
156
126
|
|
|
157
127
|
ack() {
|
|
@@ -159,11 +129,32 @@ export class AdbDaemonSocketController
|
|
|
159
129
|
}
|
|
160
130
|
|
|
161
131
|
async close(): Promise<void> {
|
|
162
|
-
|
|
132
|
+
if (this.#closed) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.#closed = true;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
this.#writableController.error(new Error("Socket closed"));
|
|
139
|
+
} catch {
|
|
140
|
+
// ignore
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
await this.#dispatcher.sendPacket(
|
|
144
|
+
AdbCommand.Close,
|
|
145
|
+
this.localId,
|
|
146
|
+
this.remoteId,
|
|
147
|
+
);
|
|
163
148
|
}
|
|
164
149
|
|
|
165
150
|
dispose() {
|
|
166
|
-
|
|
151
|
+
try {
|
|
152
|
+
this.#readableController.close();
|
|
153
|
+
} catch {
|
|
154
|
+
// ignore
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
this.#closedPromise.resolve();
|
|
167
158
|
}
|
|
168
159
|
}
|
|
169
160
|
|
|
@@ -175,11 +166,7 @@ export class AdbDaemonSocketController
|
|
|
175
166
|
* `socket.writable.abort()`, `socket.writable.getWriter().abort()`,
|
|
176
167
|
* `socket.writable.close()` or `socket.writable.getWriter().close()`.
|
|
177
168
|
*/
|
|
178
|
-
export class AdbDaemonSocket
|
|
179
|
-
implements
|
|
180
|
-
AdbDaemonSocketInfo,
|
|
181
|
-
ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>
|
|
182
|
-
{
|
|
169
|
+
export class AdbDaemonSocket implements AdbDaemonSocketInfo, AdbSocket {
|
|
183
170
|
#controller: AdbDaemonSocketController;
|
|
184
171
|
|
|
185
172
|
get localId(): number {
|
|
@@ -202,7 +189,7 @@ export class AdbDaemonSocket
|
|
|
202
189
|
return this.#controller.writable;
|
|
203
190
|
}
|
|
204
191
|
|
|
205
|
-
get closed():
|
|
192
|
+
get closed(): Promise<void> {
|
|
206
193
|
return this.#controller.closed;
|
|
207
194
|
}
|
|
208
195
|
|
package/src/daemon/transport.ts
CHANGED
|
@@ -27,20 +27,26 @@ import { AdbCommand, calculateChecksum } from "./packet.js";
|
|
|
27
27
|
|
|
28
28
|
export const ADB_DAEMON_VERSION_OMIT_CHECKSUM = 0x01000001;
|
|
29
29
|
|
|
30
|
+
export type AdbDaemonConnection = ReadableWritablePair<
|
|
31
|
+
AdbPacketData,
|
|
32
|
+
Consumable<AdbPacketInit>
|
|
33
|
+
>;
|
|
34
|
+
|
|
30
35
|
interface AdbDaemonAuthenticationOptions {
|
|
31
36
|
serial: string;
|
|
32
|
-
connection:
|
|
37
|
+
connection: AdbDaemonConnection;
|
|
33
38
|
credentialStore: AdbCredentialStore;
|
|
34
39
|
authenticators?: AdbAuthenticator[];
|
|
35
40
|
/**
|
|
36
41
|
* Whether to preserve the connection open after the `AdbDaemonTransport` is closed.
|
|
37
42
|
*/
|
|
38
43
|
preserveConnection?: boolean | undefined;
|
|
44
|
+
debugSlowRead?: boolean | undefined;
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
interface AdbDaemonSocketConnectorConstructionOptions {
|
|
42
48
|
serial: string;
|
|
43
|
-
connection:
|
|
49
|
+
connection: AdbDaemonConnection;
|
|
44
50
|
version: number;
|
|
45
51
|
maxPayloadSize: number;
|
|
46
52
|
banner: string;
|
|
@@ -48,6 +54,7 @@ interface AdbDaemonSocketConnectorConstructionOptions {
|
|
|
48
54
|
* Whether to preserve the connection open after the `AdbDaemonTransport` is closed.
|
|
49
55
|
*/
|
|
50
56
|
preserveConnection?: boolean | undefined;
|
|
57
|
+
debugSlowRead?: boolean | undefined;
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
export class AdbDaemonTransport implements AdbTransport {
|
|
@@ -64,7 +71,7 @@ export class AdbDaemonTransport implements AdbTransport {
|
|
|
64
71
|
connection,
|
|
65
72
|
credentialStore,
|
|
66
73
|
authenticators = ADB_DEFAULT_AUTHENTICATORS,
|
|
67
|
-
|
|
74
|
+
...options
|
|
68
75
|
}: AdbDaemonAuthenticationOptions): Promise<AdbDaemonTransport> {
|
|
69
76
|
// Initially, set to highest-supported version and payload size.
|
|
70
77
|
let version = 0x01000001;
|
|
@@ -94,9 +101,8 @@ export class AdbDaemonTransport implements AdbTransport {
|
|
|
94
101
|
resolver.resolve(decodeUtf8(packet.payload));
|
|
95
102
|
break;
|
|
96
103
|
case AdbCommand.Auth: {
|
|
97
|
-
const response =
|
|
98
|
-
packet
|
|
99
|
-
);
|
|
104
|
+
const response =
|
|
105
|
+
await authProcessor.process(packet);
|
|
100
106
|
await sendPacket(response);
|
|
101
107
|
break;
|
|
102
108
|
}
|
|
@@ -189,10 +195,15 @@ export class AdbDaemonTransport implements AdbTransport {
|
|
|
189
195
|
version,
|
|
190
196
|
maxPayloadSize,
|
|
191
197
|
banner,
|
|
192
|
-
|
|
198
|
+
...options,
|
|
193
199
|
});
|
|
194
200
|
}
|
|
195
201
|
|
|
202
|
+
#connection: AdbDaemonConnection;
|
|
203
|
+
get connection() {
|
|
204
|
+
return this.#connection;
|
|
205
|
+
}
|
|
206
|
+
|
|
196
207
|
readonly #dispatcher: AdbPacketDispatcher;
|
|
197
208
|
|
|
198
209
|
#serial: string;
|
|
@@ -205,9 +216,8 @@ export class AdbDaemonTransport implements AdbTransport {
|
|
|
205
216
|
return this.#protocolVersion;
|
|
206
217
|
}
|
|
207
218
|
|
|
208
|
-
#maxPayloadSize: number;
|
|
209
219
|
get maxPayloadSize() {
|
|
210
|
-
return this.#maxPayloadSize;
|
|
220
|
+
return this.#dispatcher.options.maxPayloadSize;
|
|
211
221
|
}
|
|
212
222
|
|
|
213
223
|
#banner: AdbBanner;
|
|
@@ -223,11 +233,11 @@ export class AdbDaemonTransport implements AdbTransport {
|
|
|
223
233
|
serial,
|
|
224
234
|
connection,
|
|
225
235
|
version,
|
|
226
|
-
maxPayloadSize,
|
|
227
236
|
banner,
|
|
228
|
-
|
|
237
|
+
...options
|
|
229
238
|
}: AdbDaemonSocketConnectorConstructionOptions) {
|
|
230
239
|
this.#serial = serial;
|
|
240
|
+
this.#connection = connection;
|
|
231
241
|
this.#banner = AdbBanner.parse(banner);
|
|
232
242
|
|
|
233
243
|
let calculateChecksum: boolean;
|
|
@@ -243,12 +253,10 @@ export class AdbDaemonTransport implements AdbTransport {
|
|
|
243
253
|
this.#dispatcher = new AdbPacketDispatcher(connection, {
|
|
244
254
|
calculateChecksum,
|
|
245
255
|
appendNullToServiceString,
|
|
246
|
-
|
|
247
|
-
preserveConnection,
|
|
256
|
+
...options,
|
|
248
257
|
});
|
|
249
258
|
|
|
250
259
|
this.#protocolVersion = version;
|
|
251
|
-
this.#maxPayloadSize = maxPayloadSize;
|
|
252
260
|
}
|
|
253
261
|
|
|
254
262
|
connect(service: string): ValueOrPromise<AdbSocket> {
|