@yume-chan/adb 0.0.19 → 0.0.20
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 +15 -1
- package/README.md +220 -103
- package/esm/adb.d.ts +24 -44
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +14 -203
- package/esm/adb.js.map +1 -1
- package/esm/banner.d.ts +17 -0
- package/esm/banner.d.ts.map +1 -0
- package/esm/banner.js +67 -0
- package/esm/banner.js.map +1 -0
- package/esm/commands/power.d.ts +1 -1
- package/esm/commands/power.js +2 -2
- package/esm/commands/reverse.d.ts +17 -18
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +53 -48
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/protocols/none.d.ts +3 -8
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js +16 -16
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +3 -9
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +48 -42
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +1 -2
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/list.js +2 -2
- package/esm/commands/sync/push.d.ts +14 -3
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +8 -8
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.js +1 -1
- package/esm/commands/sync/response.d.ts +3 -3
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +3 -3
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +8 -13
- package/esm/commands/sync/socket.d.ts.map +1 -1
- package/esm/commands/sync/socket.js +32 -29
- package/esm/commands/sync/socket.js.map +1 -1
- package/esm/commands/sync/stat.js +2 -2
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +11 -18
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +19 -23
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts +2 -2
- package/esm/commands/tcpip.d.ts.map +1 -1
- package/esm/commands/tcpip.js +4 -2
- package/esm/commands/tcpip.js.map +1 -1
- package/esm/{auth.d.ts → daemon/auth.d.ts} +1 -2
- package/esm/daemon/auth.d.ts.map +1 -0
- package/esm/{auth.js → daemon/auth.js} +14 -14
- package/esm/daemon/auth.js.map +1 -0
- package/esm/daemon/connection.d.ts +11 -0
- package/esm/daemon/connection.d.ts.map +1 -0
- package/esm/daemon/connection.js +2 -0
- package/esm/daemon/connection.js.map +1 -0
- package/esm/{crypto.d.ts → daemon/crypto.d.ts} +5 -5
- package/esm/daemon/crypto.d.ts.map +1 -0
- package/esm/{crypto.js → daemon/crypto.js} +23 -27
- package/esm/daemon/crypto.js.map +1 -0
- package/esm/{backend.d.ts → daemon/device.d.ts} +2 -2
- package/esm/daemon/device.d.ts.map +1 -0
- package/esm/daemon/device.js +2 -0
- package/esm/daemon/device.js.map +1 -0
- package/esm/{socket → daemon}/dispatcher.d.ts +8 -26
- package/esm/daemon/dispatcher.d.ts.map +1 -0
- package/esm/{socket → daemon}/dispatcher.js +65 -63
- package/esm/daemon/dispatcher.js.map +1 -0
- package/esm/daemon/index.d.ts +8 -0
- package/esm/daemon/index.d.ts.map +1 -0
- package/esm/daemon/index.js +8 -0
- package/esm/daemon/index.js.map +1 -0
- package/esm/{packet.d.ts → daemon/packet.d.ts} +4 -4
- package/esm/daemon/packet.d.ts.map +1 -0
- package/esm/{packet.js → daemon/packet.js} +1 -1
- package/esm/daemon/packet.js.map +1 -0
- package/esm/{socket → daemon}/socket.d.ts +15 -17
- package/esm/daemon/socket.d.ts.map +1 -0
- package/esm/{socket → daemon}/socket.js +38 -35
- package/esm/daemon/socket.js.map +1 -0
- package/esm/daemon/transport.d.ts +45 -0
- package/esm/daemon/transport.d.ts.map +1 -0
- package/esm/daemon/transport.js +184 -0
- package/esm/daemon/transport.js.map +1 -0
- package/esm/index.d.ts +3 -5
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +3 -5
- package/esm/index.js.map +1 -1
- package/esm/server/client.d.ts +78 -0
- package/esm/server/client.d.ts.map +1 -0
- package/esm/server/client.js +329 -0
- package/esm/server/client.js.map +1 -0
- package/esm/server/index.d.ts +3 -0
- package/esm/server/index.d.ts.map +1 -0
- package/esm/server/index.js +3 -0
- package/esm/server/index.js.map +1 -0
- package/esm/server/transport.d.ts +19 -0
- package/esm/server/transport.d.ts.map +1 -0
- package/esm/server/transport.js +44 -0
- package/esm/server/transport.js.map +1 -0
- package/esm/utils/auto-reset-event.d.ts +1 -2
- package/esm/utils/auto-reset-event.d.ts.map +1 -1
- package/esm/utils/auto-reset-event.js +12 -12
- package/esm/utils/auto-reset-event.js.map +1 -1
- package/esm/utils/base64.js +5 -5
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/conditional-variable.d.ts +1 -2
- package/esm/utils/conditional-variable.d.ts.map +1 -1
- package/esm/utils/conditional-variable.js +10 -10
- package/esm/utils/conditional-variable.js.map +1 -1
- package/esm/utils/hex.d.ts +3 -0
- package/esm/utils/hex.d.ts.map +1 -0
- package/esm/utils/hex.js +55 -0
- package/esm/utils/hex.js.map +1 -0
- package/esm/utils/index.d.ts +2 -0
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +2 -0
- package/esm/utils/index.js.map +1 -1
- package/esm/utils/no-op.d.ts +7 -0
- package/esm/utils/no-op.d.ts.map +1 -0
- package/esm/utils/no-op.js +12 -0
- package/esm/utils/no-op.js.map +1 -0
- package/package.json +11 -10
- package/src/adb.ts +41 -252
- package/src/banner.ts +82 -0
- package/src/commands/power.ts +2 -2
- package/src/commands/reverse.ts +68 -73
- package/src/commands/subprocess/protocols/none.ts +17 -18
- package/src/commands/subprocess/protocols/shell.ts +54 -56
- package/src/commands/subprocess/protocols/types.ts +1 -2
- package/src/commands/sync/list.ts +2 -2
- package/src/commands/sync/push.ts +22 -10
- package/src/commands/sync/request.ts +1 -1
- package/src/commands/sync/response.ts +6 -6
- package/src/commands/sync/socket.ts +37 -35
- package/src/commands/sync/sync.ts +25 -28
- package/src/commands/tcpip.ts +6 -4
- package/src/{auth.ts → daemon/auth.ts} +17 -17
- package/src/{crypto.ts → daemon/crypto.ts} +25 -33
- package/src/{backend.ts → daemon/device.ts} +1 -1
- package/src/{socket → daemon}/dispatcher.ts +71 -78
- package/src/daemon/index.ts +7 -0
- package/src/{packet.ts → daemon/packet.ts} +5 -5
- package/src/{socket → daemon}/socket.ts +50 -44
- package/src/daemon/transport.ts +269 -0
- package/src/index.ts +3 -5
- package/src/server/client.ts +476 -0
- package/src/server/index.ts +2 -0
- package/src/server/transport.ts +77 -0
- package/src/utils/auto-reset-event.ts +12 -12
- package/src/utils/conditional-variable.ts +10 -10
- package/src/utils/hex.ts +58 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/no-op.ts +12 -0
- package/tsconfig.build.json +12 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/auth.d.ts.map +0 -1
- package/esm/auth.js.map +0 -1
- package/esm/backend.d.ts.map +0 -1
- package/esm/backend.js +0 -2
- package/esm/backend.js.map +0 -1
- package/esm/commands/install.d.ts +0 -10
- package/esm/commands/install.d.ts.map +0 -1
- package/esm/commands/install.js +0 -29
- package/esm/commands/install.js.map +0 -1
- package/esm/crypto.d.ts.map +0 -1
- package/esm/crypto.js.map +0 -1
- package/esm/packet.d.ts.map +0 -1
- package/esm/packet.js.map +0 -1
- package/esm/socket/dispatcher.d.ts.map +0 -1
- package/esm/socket/dispatcher.js.map +0 -1
- package/esm/socket/index.d.ts +0 -3
- package/esm/socket/index.d.ts.map +0 -1
- package/esm/socket/index.js +0 -3
- package/esm/socket/index.js.map +0 -1
- package/esm/socket/socket.d.ts.map +0 -1
- package/esm/socket/socket.js.map +0 -1
- package/src/socket/index.ts +0 -2
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AsyncOperationManager, PromiseResolver } from "@yume-chan/async";
|
|
2
|
-
import type { RemoveEventListener } from "@yume-chan/event";
|
|
3
2
|
import type {
|
|
4
3
|
Consumable,
|
|
5
4
|
ReadableWritablePair,
|
|
@@ -10,15 +9,14 @@ import {
|
|
|
10
9
|
ConsumableWritableStream,
|
|
11
10
|
WritableStream,
|
|
12
11
|
} from "@yume-chan/stream-extra";
|
|
13
|
-
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
14
12
|
import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct";
|
|
15
13
|
|
|
16
|
-
import type {
|
|
17
|
-
import {
|
|
18
|
-
import { decodeUtf8, encodeUtf8 } from "../utils/index.js";
|
|
14
|
+
import type { AdbIncomingSocketHandler, AdbSocket, Closeable } from "../adb.js";
|
|
15
|
+
import { decodeUtf8, encodeUtf8, unreachable } from "../utils/index.js";
|
|
19
16
|
|
|
20
|
-
import type {
|
|
21
|
-
import {
|
|
17
|
+
import type { AdbPacketData, AdbPacketInit } from "./packet.js";
|
|
18
|
+
import { AdbCommand, calculateChecksum } from "./packet.js";
|
|
19
|
+
import { AdbDaemonSocketController } from "./socket.js";
|
|
22
20
|
|
|
23
21
|
export interface AdbPacketDispatcherOptions {
|
|
24
22
|
calculateChecksum: boolean;
|
|
@@ -32,14 +30,6 @@ export interface AdbPacketDispatcherOptions {
|
|
|
32
30
|
maxPayloadSize: number;
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
export type AdbIncomingSocketHandler = (
|
|
36
|
-
socket: AdbSocket
|
|
37
|
-
) => ValueOrPromise<boolean>;
|
|
38
|
-
|
|
39
|
-
export interface Closeable {
|
|
40
|
-
close(): ValueOrPromise<void>;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
33
|
/**
|
|
44
34
|
* The dispatcher is the "dumb" part of the connection handling logic.
|
|
45
35
|
*
|
|
@@ -53,25 +43,24 @@ export interface Closeable {
|
|
|
53
43
|
export class AdbPacketDispatcher implements Closeable {
|
|
54
44
|
// ADB socket id starts from 1
|
|
55
45
|
// (0 means open failed)
|
|
56
|
-
|
|
46
|
+
readonly #initializers = new AsyncOperationManager(1);
|
|
57
47
|
/**
|
|
58
48
|
* Socket local ID to the socket controller.
|
|
59
49
|
*/
|
|
60
|
-
|
|
50
|
+
readonly #sockets = new Map<number, AdbDaemonSocketController>();
|
|
61
51
|
|
|
62
|
-
|
|
52
|
+
#writer: WritableStreamDefaultWriter<Consumable<AdbPacketInit>>;
|
|
63
53
|
|
|
64
54
|
public readonly options: AdbPacketDispatcherOptions;
|
|
65
55
|
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
#closed = false;
|
|
57
|
+
#disconnected = new PromiseResolver<void>();
|
|
68
58
|
public get disconnected() {
|
|
69
|
-
return this.
|
|
59
|
+
return this.#disconnected.promise;
|
|
70
60
|
}
|
|
71
61
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
private _abortController = new AbortController();
|
|
62
|
+
#incomingSocketHandlers = new Map<string, AdbIncomingSocketHandler>();
|
|
63
|
+
#readAbortController = new AbortController();
|
|
75
64
|
|
|
76
65
|
public constructor(
|
|
77
66
|
connection: ReadableWritablePair<
|
|
@@ -94,8 +83,8 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
94
83
|
await this.handleClose(packet);
|
|
95
84
|
break;
|
|
96
85
|
case AdbCommand.Write:
|
|
97
|
-
if (this
|
|
98
|
-
await this
|
|
86
|
+
if (this.#sockets.has(packet.arg1)) {
|
|
87
|
+
await this.#sockets
|
|
99
88
|
.get(packet.arg1)!
|
|
100
89
|
.enqueue(packet.payload);
|
|
101
90
|
await this.sendPacket(
|
|
@@ -131,7 +120,7 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
131
120
|
// it's still possible to create another ADB connection.
|
|
132
121
|
// So don't close `readable` here.
|
|
133
122
|
preventCancel: true,
|
|
134
|
-
signal: this.
|
|
123
|
+
signal: this.#readAbortController.signal,
|
|
135
124
|
}
|
|
136
125
|
)
|
|
137
126
|
.then(
|
|
@@ -139,23 +128,23 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
139
128
|
this.dispose();
|
|
140
129
|
},
|
|
141
130
|
(e) => {
|
|
142
|
-
if (!this
|
|
143
|
-
this.
|
|
131
|
+
if (!this.#closed) {
|
|
132
|
+
this.#disconnected.reject(e);
|
|
144
133
|
}
|
|
145
134
|
this.dispose();
|
|
146
135
|
}
|
|
147
136
|
);
|
|
148
137
|
|
|
149
|
-
this
|
|
138
|
+
this.#writer = connection.writable.getWriter();
|
|
150
139
|
}
|
|
151
140
|
|
|
152
141
|
private handleOk(packet: AdbPacketData) {
|
|
153
|
-
if (this
|
|
142
|
+
if (this.#initializers.resolve(packet.arg1, packet.arg0)) {
|
|
154
143
|
// Device successfully created the socket
|
|
155
144
|
return;
|
|
156
145
|
}
|
|
157
146
|
|
|
158
|
-
const socket = this
|
|
147
|
+
const socket = this.#sockets.get(packet.arg1);
|
|
159
148
|
if (socket) {
|
|
160
149
|
// Device has received last `WRTE` to the socket
|
|
161
150
|
socket.ack();
|
|
@@ -171,7 +160,7 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
171
160
|
// If the socket is still pending
|
|
172
161
|
if (
|
|
173
162
|
packet.arg0 === 0 &&
|
|
174
|
-
this
|
|
163
|
+
this.#initializers.reject(
|
|
175
164
|
packet.arg1,
|
|
176
165
|
new Error("Socket open failed")
|
|
177
166
|
)
|
|
@@ -192,7 +181,7 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
192
181
|
*/
|
|
193
182
|
|
|
194
183
|
// Ignore `arg0` and search for the socket
|
|
195
|
-
const socket = this
|
|
184
|
+
const socket = this.#sockets.get(packet.arg1);
|
|
196
185
|
if (socket) {
|
|
197
186
|
// The device want to close the socket
|
|
198
187
|
if (!socket.closed) {
|
|
@@ -203,7 +192,7 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
203
192
|
);
|
|
204
193
|
}
|
|
205
194
|
await socket.dispose();
|
|
206
|
-
this
|
|
195
|
+
this.#sockets.delete(packet.arg1);
|
|
207
196
|
return;
|
|
208
197
|
}
|
|
209
198
|
|
|
@@ -212,68 +201,74 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
212
201
|
// the device may also respond with two `CLSE` packets.
|
|
213
202
|
}
|
|
214
203
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
* @param handler A function to call with new incoming sockets. It must return `true` if it accepts the socket.
|
|
218
|
-
* @returns A function to remove the handler.
|
|
219
|
-
*/
|
|
220
|
-
public onIncomingSocket(
|
|
204
|
+
public addReverseTunnel(
|
|
205
|
+
service: string,
|
|
221
206
|
handler: AdbIncomingSocketHandler
|
|
222
|
-
)
|
|
223
|
-
this.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
207
|
+
) {
|
|
208
|
+
this.#incomingSocketHandlers.set(service, handler);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
public removeReverseTunnel(address: string) {
|
|
212
|
+
this.#incomingSocketHandlers.delete(address);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
public clearReverseTunnels() {
|
|
216
|
+
this.#incomingSocketHandlers.clear();
|
|
229
217
|
}
|
|
230
218
|
|
|
231
219
|
private async handleOpen(packet: AdbPacketData) {
|
|
232
220
|
// `AsyncOperationManager` doesn't support skipping IDs
|
|
233
221
|
// Use `add` + `resolve` to simulate this behavior
|
|
234
|
-
const [localId] = this
|
|
235
|
-
this
|
|
222
|
+
const [localId] = this.#initializers.add<number>();
|
|
223
|
+
this.#initializers.resolve(localId, undefined);
|
|
236
224
|
|
|
237
225
|
const remoteId = packet.arg0;
|
|
238
|
-
|
|
226
|
+
let service = decodeUtf8(packet.payload);
|
|
227
|
+
if (service.endsWith("\0")) {
|
|
228
|
+
service = service.substring(0, service.length - 1);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const handler = this.#incomingSocketHandlers.get(service);
|
|
232
|
+
if (!handler) {
|
|
233
|
+
await this.sendPacket(AdbCommand.Close, 0, remoteId);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
239
236
|
|
|
240
|
-
const controller = new
|
|
237
|
+
const controller = new AdbDaemonSocketController({
|
|
241
238
|
dispatcher: this,
|
|
242
239
|
localId,
|
|
243
240
|
remoteId,
|
|
244
241
|
localCreated: false,
|
|
245
|
-
|
|
242
|
+
service,
|
|
246
243
|
});
|
|
247
244
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
245
|
+
try {
|
|
246
|
+
await handler(controller.socket);
|
|
247
|
+
this.#sockets.set(localId, controller);
|
|
248
|
+
await this.sendPacket(AdbCommand.OK, localId, remoteId);
|
|
249
|
+
} catch (e) {
|
|
250
|
+
await this.sendPacket(AdbCommand.Close, 0, remoteId);
|
|
254
251
|
}
|
|
255
|
-
|
|
256
|
-
await this.sendPacket(AdbCommand.Close, 0, remoteId);
|
|
257
252
|
}
|
|
258
253
|
|
|
259
|
-
public async createSocket(
|
|
254
|
+
public async createSocket(service: string): Promise<AdbSocket> {
|
|
260
255
|
if (this.options.appendNullToServiceString) {
|
|
261
|
-
|
|
256
|
+
service += "\0";
|
|
262
257
|
}
|
|
263
258
|
|
|
264
|
-
const [localId, initializer] = this
|
|
265
|
-
await this.sendPacket(AdbCommand.Open, localId, 0,
|
|
259
|
+
const [localId, initializer] = this.#initializers.add<number>();
|
|
260
|
+
await this.sendPacket(AdbCommand.Open, localId, 0, service);
|
|
266
261
|
|
|
267
262
|
// Fulfilled by `handleOk`
|
|
268
263
|
const remoteId = await initializer;
|
|
269
|
-
const controller = new
|
|
264
|
+
const controller = new AdbDaemonSocketController({
|
|
270
265
|
dispatcher: this,
|
|
271
266
|
localId,
|
|
272
267
|
remoteId,
|
|
273
268
|
localCreated: true,
|
|
274
|
-
|
|
269
|
+
service,
|
|
275
270
|
});
|
|
276
|
-
this
|
|
271
|
+
this.#sockets.set(localId, controller);
|
|
277
272
|
|
|
278
273
|
return controller.socket;
|
|
279
274
|
}
|
|
@@ -292,7 +287,7 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
292
287
|
throw new Error("payload too large");
|
|
293
288
|
}
|
|
294
289
|
|
|
295
|
-
await ConsumableWritableStream.write(this
|
|
290
|
+
await ConsumableWritableStream.write(this.#writer, {
|
|
296
291
|
command,
|
|
297
292
|
arg0,
|
|
298
293
|
arg1,
|
|
@@ -307,26 +302,24 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
307
302
|
public async close() {
|
|
308
303
|
// Send `CLSE` packets for all sockets
|
|
309
304
|
await Promise.all(
|
|
310
|
-
Array.from(this
|
|
305
|
+
Array.from(this.#sockets.values(), (socket) => socket.close())
|
|
311
306
|
);
|
|
312
307
|
|
|
313
308
|
// Stop receiving
|
|
314
309
|
// It's possible that we haven't received all `CLSE` confirm packets,
|
|
315
310
|
// but it doesn't matter, the next connection can cope with them.
|
|
316
|
-
this
|
|
317
|
-
this.
|
|
318
|
-
this.
|
|
311
|
+
this.#closed = true;
|
|
312
|
+
this.#readAbortController.abort();
|
|
313
|
+
this.#writer.releaseLock();
|
|
319
314
|
|
|
320
315
|
// `pipe().then()` will call `dispose`
|
|
321
316
|
}
|
|
322
317
|
|
|
323
318
|
private dispose() {
|
|
324
|
-
for (const socket of this
|
|
325
|
-
socket.dispose().catch(
|
|
326
|
-
void e;
|
|
327
|
-
});
|
|
319
|
+
for (const socket of this.#sockets.values()) {
|
|
320
|
+
socket.dispose().catch(unreachable);
|
|
328
321
|
}
|
|
329
322
|
|
|
330
|
-
this.
|
|
323
|
+
this.#disconnected.resolve();
|
|
331
324
|
}
|
|
332
325
|
}
|
|
@@ -23,7 +23,7 @@ export type AdbPacketHeader = (typeof AdbPacketHeader)["TDeserializeResult"];
|
|
|
23
23
|
type AdbPacketHeaderInit = (typeof AdbPacketHeader)["TInit"];
|
|
24
24
|
|
|
25
25
|
export const AdbPacket = new Struct({ littleEndian: true })
|
|
26
|
-
.
|
|
26
|
+
.concat(AdbPacketHeader)
|
|
27
27
|
.uint8Array("payload", { lengthField: "payloadLength" });
|
|
28
28
|
|
|
29
29
|
export type AdbPacket = (typeof AdbPacket)["TDeserializeResult"];
|
|
@@ -31,11 +31,11 @@ export type AdbPacket = (typeof AdbPacket)["TDeserializeResult"];
|
|
|
31
31
|
/**
|
|
32
32
|
* `AdbPacketData` contains all the useful fields of `AdbPacket`.
|
|
33
33
|
*
|
|
34
|
-
* `
|
|
35
|
-
*
|
|
34
|
+
* `AdvDaemonConnection#connect` will return a `ReadableStream<AdbPacketData>`,
|
|
35
|
+
* allow each connection to encode `AdbPacket` in different methods.
|
|
36
36
|
*
|
|
37
|
-
* `
|
|
38
|
-
* however, `
|
|
37
|
+
* `AdbDaemonConnection#connect` will return a `WritableStream<AdbPacketInit>`,
|
|
38
|
+
* however, `AdbDaemonTransport` will transform `AdbPacketData` to `AdbPacketInit` for you,
|
|
39
39
|
* so `AdbSocket#writable#write` only needs `AdbPacketData`.
|
|
40
40
|
*/
|
|
41
41
|
export type AdbPacketData = Omit<
|
|
@@ -15,27 +15,29 @@ import {
|
|
|
15
15
|
pipeFrom,
|
|
16
16
|
} from "@yume-chan/stream-extra";
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import type { Closeable } from "../adb.js";
|
|
19
19
|
|
|
20
|
-
import type { AdbPacketDispatcher
|
|
20
|
+
import type { AdbPacketDispatcher } from "./dispatcher.js";
|
|
21
|
+
import { AdbCommand } from "./packet.js";
|
|
21
22
|
|
|
22
|
-
export interface
|
|
23
|
+
export interface AdbDaemonSocketInfo {
|
|
23
24
|
localId: number;
|
|
24
25
|
remoteId: number;
|
|
25
26
|
|
|
26
27
|
localCreated: boolean;
|
|
27
|
-
|
|
28
|
+
service: string;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
export interface
|
|
31
|
+
export interface AdbDaemonSocketConstructionOptions
|
|
32
|
+
extends AdbDaemonSocketInfo {
|
|
31
33
|
dispatcher: AdbPacketDispatcher;
|
|
32
34
|
|
|
33
35
|
highWaterMark?: number | undefined;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
export class
|
|
38
|
+
export class AdbDaemonSocketController
|
|
37
39
|
implements
|
|
38
|
-
|
|
40
|
+
AdbDaemonSocketInfo,
|
|
39
41
|
ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>,
|
|
40
42
|
Closeable,
|
|
41
43
|
Disposable
|
|
@@ -45,47 +47,47 @@ export class AdbSocketController
|
|
|
45
47
|
public readonly localId!: number;
|
|
46
48
|
public readonly remoteId!: number;
|
|
47
49
|
public readonly localCreated!: boolean;
|
|
48
|
-
public readonly
|
|
50
|
+
public readonly service!: string;
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
#duplex: DuplexStreamFactory<Uint8Array, Consumable<Uint8Array>>;
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
#readable: ReadableStream<Uint8Array>;
|
|
55
|
+
#readableController!: PushReadableStreamController<Uint8Array>;
|
|
54
56
|
public get readable() {
|
|
55
|
-
return this
|
|
57
|
+
return this.#readable;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
#writePromise: PromiseResolver<void> | undefined;
|
|
59
61
|
public readonly writable: WritableStream<Consumable<Uint8Array>>;
|
|
60
62
|
|
|
61
|
-
|
|
63
|
+
#closed = false;
|
|
62
64
|
/**
|
|
63
65
|
* Whether the socket is half-closed (i.e. the local side initiated the close).
|
|
64
66
|
*
|
|
65
67
|
* It's only used by dispatcher to avoid sending another `CLSE` packet to remote.
|
|
66
68
|
*/
|
|
67
69
|
public get closed() {
|
|
68
|
-
return this
|
|
70
|
+
return this.#closed;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
private _socket:
|
|
73
|
+
private _socket: AdbDaemonSocket;
|
|
72
74
|
public get socket() {
|
|
73
75
|
return this._socket;
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
public constructor(options:
|
|
78
|
+
public constructor(options: AdbDaemonSocketConstructionOptions) {
|
|
77
79
|
Object.assign(this, options);
|
|
78
80
|
|
|
79
81
|
// Check this image to help you understand the stream graph
|
|
80
82
|
// cspell: disable-next-line
|
|
81
83
|
// https://www.plantuml.com/plantuml/png/TL0zoeGm4ErpYc3l5JxyS0yWM6mX5j4C6p4cxcJ25ejttuGX88ZftizxUKmJI275pGhXl0PP_UkfK_CAz5Z2hcWsW9Ny2fdU4C1f5aSchFVxA8vJjlTPRhqZzDQMRB7AklwJ0xXtX0ZSKH1h24ghoKAdGY23FhxC4nS2pDvxzIvxb-8THU0XlEQJ-ZB7SnXTAvc_LhOckhMdLBnbtndpb-SB7a8q2SRD_W00
|
|
82
84
|
|
|
83
|
-
this
|
|
85
|
+
this.#duplex = new DuplexStreamFactory<
|
|
84
86
|
Uint8Array,
|
|
85
87
|
Consumable<Uint8Array>
|
|
86
88
|
>({
|
|
87
89
|
close: async () => {
|
|
88
|
-
this
|
|
90
|
+
this.#closed = true;
|
|
89
91
|
|
|
90
92
|
await this.dispatcher.sendPacket(
|
|
91
93
|
AdbCommand.Close,
|
|
@@ -98,14 +100,14 @@ export class AdbSocketController
|
|
|
98
100
|
},
|
|
99
101
|
dispose: () => {
|
|
100
102
|
// Error out the pending writes
|
|
101
|
-
this
|
|
103
|
+
this.#writePromise?.reject(new Error("Socket closed"));
|
|
102
104
|
},
|
|
103
105
|
});
|
|
104
106
|
|
|
105
|
-
this
|
|
107
|
+
this.#readable = this.#duplex.wrapReadable(
|
|
106
108
|
new PushReadableStream(
|
|
107
109
|
(controller) => {
|
|
108
|
-
this
|
|
110
|
+
this.#readableController = controller;
|
|
109
111
|
},
|
|
110
112
|
{
|
|
111
113
|
highWaterMark: options.highWaterMark ?? 16 * 1024,
|
|
@@ -117,47 +119,47 @@ export class AdbSocketController
|
|
|
117
119
|
);
|
|
118
120
|
|
|
119
121
|
this.writable = pipeFrom(
|
|
120
|
-
this.
|
|
122
|
+
this.#duplex.createWritable(
|
|
121
123
|
new ConsumableWritableStream<Uint8Array>({
|
|
122
124
|
write: async (chunk) => {
|
|
123
125
|
// Wait for an ack packet
|
|
124
|
-
this
|
|
126
|
+
this.#writePromise = new PromiseResolver();
|
|
125
127
|
await this.dispatcher.sendPacket(
|
|
126
128
|
AdbCommand.Write,
|
|
127
129
|
this.localId,
|
|
128
130
|
this.remoteId,
|
|
129
131
|
chunk
|
|
130
132
|
);
|
|
131
|
-
await this.
|
|
133
|
+
await this.#writePromise.promise;
|
|
132
134
|
},
|
|
133
135
|
})
|
|
134
136
|
),
|
|
135
137
|
new DistributionStream(this.dispatcher.options.maxPayloadSize)
|
|
136
138
|
);
|
|
137
139
|
|
|
138
|
-
this._socket = new
|
|
140
|
+
this._socket = new AdbDaemonSocket(this);
|
|
139
141
|
}
|
|
140
142
|
|
|
141
143
|
public async enqueue(data: Uint8Array) {
|
|
142
144
|
// Consumer may abort the `ReadableStream` to close the socket,
|
|
143
145
|
// it's OK to throw away further packets in this case.
|
|
144
|
-
if (this.
|
|
146
|
+
if (this.#readableController.abortSignal.aborted) {
|
|
145
147
|
return;
|
|
146
148
|
}
|
|
147
149
|
|
|
148
|
-
await this.
|
|
150
|
+
await this.#readableController.enqueue(data);
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
public ack() {
|
|
152
|
-
this
|
|
154
|
+
this.#writePromise?.resolve();
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
public async close(): Promise<void> {
|
|
156
|
-
await this.
|
|
158
|
+
await this.#duplex.close();
|
|
157
159
|
}
|
|
158
160
|
|
|
159
161
|
public dispose() {
|
|
160
|
-
return this.
|
|
162
|
+
return this.#duplex.dispose();
|
|
161
163
|
}
|
|
162
164
|
}
|
|
163
165
|
|
|
@@ -169,38 +171,42 @@ export class AdbSocketController
|
|
|
169
171
|
* `socket.writable.abort()`, `socket.writable.getWriter().abort()`,
|
|
170
172
|
* `socket.writable.close()` or `socket.writable.getWriter().close()`.
|
|
171
173
|
*/
|
|
172
|
-
export class
|
|
174
|
+
export class AdbDaemonSocket
|
|
173
175
|
implements
|
|
174
|
-
|
|
176
|
+
AdbDaemonSocketInfo,
|
|
175
177
|
ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>
|
|
176
178
|
{
|
|
177
|
-
|
|
179
|
+
#controller: AdbDaemonSocketController;
|
|
178
180
|
|
|
179
181
|
public get localId(): number {
|
|
180
|
-
return this.
|
|
182
|
+
return this.#controller.localId;
|
|
181
183
|
}
|
|
182
184
|
public get remoteId(): number {
|
|
183
|
-
return this.
|
|
185
|
+
return this.#controller.remoteId;
|
|
184
186
|
}
|
|
185
187
|
public get localCreated(): boolean {
|
|
186
|
-
return this.
|
|
188
|
+
return this.#controller.localCreated;
|
|
187
189
|
}
|
|
188
|
-
public get
|
|
189
|
-
return this.
|
|
190
|
+
public get service(): string {
|
|
191
|
+
return this.#controller.service;
|
|
190
192
|
}
|
|
191
193
|
|
|
192
194
|
public get readable(): ReadableStream<Uint8Array> {
|
|
193
|
-
return this.
|
|
195
|
+
return this.#controller.readable;
|
|
194
196
|
}
|
|
195
197
|
public get writable(): WritableStream<Consumable<Uint8Array>> {
|
|
196
|
-
return this.
|
|
198
|
+
return this.#controller.writable;
|
|
197
199
|
}
|
|
198
200
|
|
|
199
|
-
public
|
|
200
|
-
this.
|
|
201
|
+
public get closed(): boolean {
|
|
202
|
+
return this.#controller.closed;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
public constructor(controller: AdbDaemonSocketController) {
|
|
206
|
+
this.#controller = controller;
|
|
201
207
|
}
|
|
202
208
|
|
|
203
209
|
public close() {
|
|
204
|
-
return this.
|
|
210
|
+
return this.#controller.close();
|
|
205
211
|
}
|
|
206
212
|
}
|