@yume-chan/adb 0.0.18 → 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 +54 -0
- package/CHANGELOG.md +25 -1
- package/README.md +220 -103
- package/esm/adb.d.ts +43 -60
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +68 -249
- 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/base.d.ts +6 -6
- package/esm/commands/base.d.ts.map +1 -1
- package/esm/commands/base.js +8 -8
- package/esm/commands/framebuffer.d.ts +53 -53
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +46 -46
- package/esm/commands/framebuffer.js.map +1 -1
- package/esm/commands/index.d.ts +7 -8
- package/esm/commands/index.d.ts.map +1 -1
- package/esm/commands/index.js +7 -8
- package/esm/commands/index.js.map +1 -1
- package/esm/commands/power.d.ts +22 -22
- package/esm/commands/power.js +48 -48
- package/esm/commands/reverse.d.ts +40 -28
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +130 -100
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.d.ts +57 -51
- package/esm/commands/subprocess/command.d.ts.map +1 -1
- package/esm/commands/subprocess/command.js +86 -80
- package/esm/commands/subprocess/command.js.map +1 -1
- package/esm/commands/subprocess/index.d.ts +3 -3
- package/esm/commands/subprocess/index.js +3 -3
- package/esm/commands/subprocess/protocols/index.d.ts +3 -3
- package/esm/commands/subprocess/protocols/index.js +3 -3
- package/esm/commands/subprocess/protocols/none.d.ts +30 -35
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js +65 -55
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +33 -38
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +172 -162
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +48 -49
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/types.js +1 -1
- package/esm/commands/subprocess/utils.d.ts +1 -1
- package/esm/commands/subprocess/utils.js +18 -18
- package/esm/commands/sync/index.d.ts +8 -7
- package/esm/commands/sync/index.d.ts.map +1 -1
- package/esm/commands/sync/index.js +8 -7
- package/esm/commands/sync/index.js.map +1 -1
- package/esm/commands/sync/list.d.ts +42 -40
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +67 -47
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +13 -11
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +35 -37
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +57 -7
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +89 -22
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.d.ts +26 -23
- package/esm/commands/sync/request.d.ts.map +1 -1
- package/esm/commands/sync/request.js +40 -42
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +19 -19
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +54 -54
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +22 -0
- package/esm/commands/sync/socket.d.ts.map +1 -0
- package/esm/commands/sync/socket.js +69 -0
- package/esm/commands/sync/socket.js.map +1 -0
- package/esm/commands/sync/stat.d.ts +72 -72
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +116 -104
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +65 -60
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +123 -149
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts +5 -5
- package/esm/commands/tcpip.d.ts.map +1 -1
- package/esm/commands/tcpip.js +20 -18
- package/esm/commands/tcpip.js.map +1 -1
- package/esm/{auth.d.ts → daemon/auth.d.ts} +50 -51
- package/esm/daemon/auth.d.ts.map +1 -0
- package/esm/{auth.js → daemon/auth.js} +95 -96
- 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} +36 -36
- package/esm/daemon/crypto.d.ts.map +1 -0
- package/esm/{crypto.js → daemon/crypto.js} +244 -248
- package/esm/daemon/crypto.js.map +1 -0
- package/esm/daemon/device.d.ts +9 -0
- 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/daemon/dispatcher.d.ts +42 -0
- package/esm/daemon/dispatcher.d.ts.map +1 -0
- package/esm/{socket → daemon}/dispatcher.js +225 -234
- 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} +45 -46
- package/esm/daemon/packet.d.ts.map +1 -0
- package/esm/{packet.js → daemon/packet.js} +43 -48
- package/esm/daemon/packet.js.map +1 -0
- package/esm/daemon/socket.d.ts +58 -0
- package/esm/daemon/socket.d.ts.map +1 -0
- package/esm/{socket → daemon}/socket.js +121 -118
- 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/features.d.ts +10 -7
- package/esm/features.d.ts.map +1 -1
- package/esm/features.js +13 -10
- package/esm/features.js.map +1 -1
- package/esm/index.d.ts +7 -9
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +7 -9
- 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 +8 -9
- package/esm/utils/auto-reset-event.d.ts.map +1 -1
- package/esm/utils/auto-reset-event.js +33 -33
- package/esm/utils/auto-reset-event.js.map +1 -1
- package/esm/utils/base64.d.ts +27 -27
- package/esm/utils/base64.js +246 -246
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/conditional-variable.d.ts +8 -0
- package/esm/utils/conditional-variable.d.ts.map +1 -0
- package/esm/utils/conditional-variable.js +34 -0
- package/esm/utils/conditional-variable.js.map +1 -0
- 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 +6 -3
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +6 -3
- 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 +14 -12
- package/src/adb.ts +47 -248
- package/src/banner.ts +82 -0
- package/src/commands/base.ts +1 -1
- package/src/commands/framebuffer.ts +4 -4
- package/src/commands/index.ts +7 -8
- package/src/commands/power.ts +2 -2
- package/src/commands/reverse.ts +90 -70
- package/src/commands/subprocess/command.ts +12 -4
- package/src/commands/subprocess/index.ts +3 -3
- package/src/commands/subprocess/protocols/index.ts +3 -3
- package/src/commands/subprocess/protocols/none.ts +36 -23
- package/src/commands/subprocess/protocols/shell.ts +94 -74
- package/src/commands/subprocess/protocols/types.ts +7 -7
- package/src/commands/subprocess/utils.ts +1 -1
- package/src/commands/sync/index.ts +8 -7
- package/src/commands/sync/list.ts +44 -25
- package/src/commands/sync/pull.ts +40 -45
- package/src/commands/sync/push.ts +158 -39
- package/src/commands/sync/request.ts +21 -16
- package/src/commands/sync/response.ts +10 -9
- package/src/commands/sync/socket.ts +99 -0
- package/src/commands/sync/stat.ts +47 -42
- package/src/commands/sync/sync.ts +73 -116
- package/src/commands/tcpip.ts +9 -7
- package/src/{auth.ts → daemon/auth.ts} +24 -23
- package/src/{crypto.ts → daemon/crypto.ts} +25 -33
- package/src/daemon/device.ts +14 -0
- package/src/{socket → daemon}/dispatcher.ts +95 -117
- package/src/daemon/index.ts +7 -0
- package/src/daemon/packet.ts +75 -0
- package/src/{socket → daemon}/socket.ts +71 -56
- package/src/daemon/transport.ts +269 -0
- package/src/features.ts +9 -6
- 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 +14 -15
- package/src/utils/conditional-variable.ts +45 -0
- package/src/utils/hex.ts +58 -0
- package/src/utils/index.ts +6 -3
- 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 +0 -9
- 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 -4
- 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 +0 -60
- 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 +0 -60
- package/esm/socket/socket.d.ts.map +0 -1
- package/esm/socket/socket.js.map +0 -1
- package/src/backend.ts +0 -14
- package/src/commands/install.ts +0 -40
- package/src/packet.ts +0 -90
- package/src/socket/index.ts +0 -2
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { AsyncOperationManager, PromiseResolver } from "@yume-chan/async";
|
|
2
|
-
import
|
|
2
|
+
import type {
|
|
3
|
+
Consumable,
|
|
4
|
+
ReadableWritablePair,
|
|
5
|
+
WritableStreamDefaultWriter,
|
|
6
|
+
} from "@yume-chan/stream-extra";
|
|
3
7
|
import {
|
|
4
8
|
AbortController,
|
|
9
|
+
ConsumableWritableStream,
|
|
5
10
|
WritableStream,
|
|
6
|
-
type ReadableWritablePair,
|
|
7
|
-
type WritableStreamDefaultWriter,
|
|
8
11
|
} from "@yume-chan/stream-extra";
|
|
9
|
-
import { EMPTY_UINT8_ARRAY
|
|
12
|
+
import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct";
|
|
10
13
|
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
calculateChecksum,
|
|
14
|
-
type AdbPacketData,
|
|
15
|
-
type AdbPacketInit,
|
|
16
|
-
} from "../packet.js";
|
|
17
|
-
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";
|
|
18
16
|
|
|
19
|
-
import {
|
|
17
|
+
import type { AdbPacketData, AdbPacketInit } from "./packet.js";
|
|
18
|
+
import { AdbCommand, calculateChecksum } from "./packet.js";
|
|
19
|
+
import { AdbDaemonSocketController } from "./socket.js";
|
|
20
20
|
|
|
21
21
|
export interface AdbPacketDispatcherOptions {
|
|
22
22
|
calculateChecksum: boolean;
|
|
@@ -30,14 +30,6 @@ export interface AdbPacketDispatcherOptions {
|
|
|
30
30
|
maxPayloadSize: number;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export type AdbIncomingSocketHandler = (
|
|
34
|
-
socket: AdbSocket
|
|
35
|
-
) => ValueOrPromise<boolean>;
|
|
36
|
-
|
|
37
|
-
export interface Closeable {
|
|
38
|
-
close(): ValueOrPromise<void>;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
33
|
/**
|
|
42
34
|
* The dispatcher is the "dumb" part of the connection handling logic.
|
|
43
35
|
*
|
|
@@ -51,28 +43,30 @@ export interface Closeable {
|
|
|
51
43
|
export class AdbPacketDispatcher implements Closeable {
|
|
52
44
|
// ADB socket id starts from 1
|
|
53
45
|
// (0 means open failed)
|
|
54
|
-
|
|
46
|
+
readonly #initializers = new AsyncOperationManager(1);
|
|
55
47
|
/**
|
|
56
48
|
* Socket local ID to the socket controller.
|
|
57
49
|
*/
|
|
58
|
-
|
|
50
|
+
readonly #sockets = new Map<number, AdbDaemonSocketController>();
|
|
59
51
|
|
|
60
|
-
|
|
52
|
+
#writer: WritableStreamDefaultWriter<Consumable<AdbPacketInit>>;
|
|
61
53
|
|
|
62
54
|
public readonly options: AdbPacketDispatcherOptions;
|
|
63
55
|
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
#closed = false;
|
|
57
|
+
#disconnected = new PromiseResolver<void>();
|
|
66
58
|
public get disconnected() {
|
|
67
|
-
return this.
|
|
59
|
+
return this.#disconnected.promise;
|
|
68
60
|
}
|
|
69
61
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
private _abortController = new AbortController();
|
|
62
|
+
#incomingSocketHandlers = new Map<string, AdbIncomingSocketHandler>();
|
|
63
|
+
#readAbortController = new AbortController();
|
|
73
64
|
|
|
74
65
|
public constructor(
|
|
75
|
-
connection: ReadableWritablePair<
|
|
66
|
+
connection: ReadableWritablePair<
|
|
67
|
+
AdbPacketData,
|
|
68
|
+
Consumable<AdbPacketInit>
|
|
69
|
+
>,
|
|
76
70
|
options: AdbPacketDispatcherOptions
|
|
77
71
|
) {
|
|
78
72
|
this.options = options;
|
|
@@ -89,8 +83,8 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
89
83
|
await this.handleClose(packet);
|
|
90
84
|
break;
|
|
91
85
|
case AdbCommand.Write:
|
|
92
|
-
if (this
|
|
93
|
-
await this
|
|
86
|
+
if (this.#sockets.has(packet.arg1)) {
|
|
87
|
+
await this.#sockets
|
|
94
88
|
.get(packet.arg1)!
|
|
95
89
|
.enqueue(packet.payload);
|
|
96
90
|
await this.sendPacket(
|
|
@@ -126,7 +120,7 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
126
120
|
// it's still possible to create another ADB connection.
|
|
127
121
|
// So don't close `readable` here.
|
|
128
122
|
preventCancel: true,
|
|
129
|
-
signal: this.
|
|
123
|
+
signal: this.#readAbortController.signal,
|
|
130
124
|
}
|
|
131
125
|
)
|
|
132
126
|
.then(
|
|
@@ -134,23 +128,23 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
134
128
|
this.dispose();
|
|
135
129
|
},
|
|
136
130
|
(e) => {
|
|
137
|
-
if (!this
|
|
138
|
-
this.
|
|
131
|
+
if (!this.#closed) {
|
|
132
|
+
this.#disconnected.reject(e);
|
|
139
133
|
}
|
|
140
134
|
this.dispose();
|
|
141
135
|
}
|
|
142
136
|
);
|
|
143
137
|
|
|
144
|
-
this
|
|
138
|
+
this.#writer = connection.writable.getWriter();
|
|
145
139
|
}
|
|
146
140
|
|
|
147
141
|
private handleOk(packet: AdbPacketData) {
|
|
148
|
-
if (this
|
|
142
|
+
if (this.#initializers.resolve(packet.arg1, packet.arg0)) {
|
|
149
143
|
// Device successfully created the socket
|
|
150
144
|
return;
|
|
151
145
|
}
|
|
152
146
|
|
|
153
|
-
const socket = this
|
|
147
|
+
const socket = this.#sockets.get(packet.arg1);
|
|
154
148
|
if (socket) {
|
|
155
149
|
// Device has received last `WRTE` to the socket
|
|
156
150
|
socket.ack();
|
|
@@ -166,7 +160,7 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
166
160
|
// If the socket is still pending
|
|
167
161
|
if (
|
|
168
162
|
packet.arg0 === 0 &&
|
|
169
|
-
this
|
|
163
|
+
this.#initializers.reject(
|
|
170
164
|
packet.arg1,
|
|
171
165
|
new Error("Socket open failed")
|
|
172
166
|
)
|
|
@@ -187,7 +181,7 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
187
181
|
*/
|
|
188
182
|
|
|
189
183
|
// Ignore `arg0` and search for the socket
|
|
190
|
-
const socket = this
|
|
184
|
+
const socket = this.#sockets.get(packet.arg1);
|
|
191
185
|
if (socket) {
|
|
192
186
|
// The device want to close the socket
|
|
193
187
|
if (!socket.closed) {
|
|
@@ -198,7 +192,7 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
198
192
|
);
|
|
199
193
|
}
|
|
200
194
|
await socket.dispose();
|
|
201
|
-
this
|
|
195
|
+
this.#sockets.delete(packet.arg1);
|
|
202
196
|
return;
|
|
203
197
|
}
|
|
204
198
|
|
|
@@ -207,141 +201,125 @@ export class AdbPacketDispatcher implements Closeable {
|
|
|
207
201
|
// the device may also respond with two `CLSE` packets.
|
|
208
202
|
}
|
|
209
203
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
* @param handler A function to call with new incoming sockets. It must return `true` if it accepts the socket.
|
|
213
|
-
* @returns A function to remove the handler.
|
|
214
|
-
*/
|
|
215
|
-
public onIncomingSocket(
|
|
204
|
+
public addReverseTunnel(
|
|
205
|
+
service: string,
|
|
216
206
|
handler: AdbIncomingSocketHandler
|
|
217
|
-
)
|
|
218
|
-
this.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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();
|
|
224
217
|
}
|
|
225
218
|
|
|
226
219
|
private async handleOpen(packet: AdbPacketData) {
|
|
227
220
|
// `AsyncOperationManager` doesn't support skipping IDs
|
|
228
221
|
// Use `add` + `resolve` to simulate this behavior
|
|
229
|
-
const [localId] = this
|
|
230
|
-
this
|
|
222
|
+
const [localId] = this.#initializers.add<number>();
|
|
223
|
+
this.#initializers.resolve(localId, undefined);
|
|
231
224
|
|
|
232
225
|
const remoteId = packet.arg0;
|
|
233
|
-
|
|
226
|
+
let service = decodeUtf8(packet.payload);
|
|
227
|
+
if (service.endsWith("\0")) {
|
|
228
|
+
service = service.substring(0, service.length - 1);
|
|
229
|
+
}
|
|
234
230
|
|
|
235
|
-
const
|
|
231
|
+
const handler = this.#incomingSocketHandlers.get(service);
|
|
232
|
+
if (!handler) {
|
|
233
|
+
await this.sendPacket(AdbCommand.Close, 0, remoteId);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const controller = new AdbDaemonSocketController({
|
|
236
238
|
dispatcher: this,
|
|
237
239
|
localId,
|
|
238
240
|
remoteId,
|
|
239
241
|
localCreated: false,
|
|
240
|
-
|
|
242
|
+
service,
|
|
241
243
|
});
|
|
242
244
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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);
|
|
249
251
|
}
|
|
250
|
-
|
|
251
|
-
await this.sendPacket(AdbCommand.Close, 0, remoteId);
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
-
public async createSocket(
|
|
254
|
+
public async createSocket(service: string): Promise<AdbSocket> {
|
|
255
255
|
if (this.options.appendNullToServiceString) {
|
|
256
|
-
|
|
256
|
+
service += "\0";
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
const [localId, initializer] = this
|
|
260
|
-
await this.sendPacket(AdbCommand.Open, localId, 0,
|
|
259
|
+
const [localId, initializer] = this.#initializers.add<number>();
|
|
260
|
+
await this.sendPacket(AdbCommand.Open, localId, 0, service);
|
|
261
261
|
|
|
262
262
|
// Fulfilled by `handleOk`
|
|
263
263
|
const remoteId = await initializer;
|
|
264
|
-
const controller = new
|
|
264
|
+
const controller = new AdbDaemonSocketController({
|
|
265
265
|
dispatcher: this,
|
|
266
266
|
localId,
|
|
267
267
|
remoteId,
|
|
268
268
|
localCreated: true,
|
|
269
|
-
|
|
269
|
+
service,
|
|
270
270
|
});
|
|
271
|
-
this
|
|
271
|
+
this.#sockets.set(localId, controller);
|
|
272
272
|
|
|
273
273
|
return controller.socket;
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
-
public sendPacket(
|
|
277
|
-
public sendPacket(
|
|
276
|
+
public async sendPacket(
|
|
278
277
|
command: AdbCommand,
|
|
279
278
|
arg0: number,
|
|
280
279
|
arg1: number,
|
|
281
|
-
payload?: string | Uint8Array
|
|
282
|
-
): Promise<void>;
|
|
283
|
-
public async sendPacket(
|
|
284
|
-
packetOrCommand: AdbPacketInit | AdbCommand,
|
|
285
|
-
arg0?: number,
|
|
286
|
-
arg1?: number,
|
|
287
280
|
payload: string | Uint8Array = EMPTY_UINT8_ARRAY
|
|
288
281
|
): Promise<void> {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
init = packetOrCommand as AdbPacketInit;
|
|
292
|
-
} else {
|
|
293
|
-
if (typeof payload === "string") {
|
|
294
|
-
payload = encodeUtf8(payload);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
init = {
|
|
298
|
-
command: packetOrCommand as AdbCommand,
|
|
299
|
-
arg0: arg0,
|
|
300
|
-
arg1: arg1 as number,
|
|
301
|
-
payload,
|
|
302
|
-
};
|
|
282
|
+
if (typeof payload === "string") {
|
|
283
|
+
payload = encodeUtf8(payload);
|
|
303
284
|
}
|
|
304
285
|
|
|
305
|
-
if (
|
|
306
|
-
init.payload &&
|
|
307
|
-
init.payload.byteLength > this.options.maxPayloadSize
|
|
308
|
-
) {
|
|
286
|
+
if (payload.byteLength > this.options.maxPayloadSize) {
|
|
309
287
|
throw new Error("payload too large");
|
|
310
288
|
}
|
|
311
289
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
290
|
+
await ConsumableWritableStream.write(this.#writer, {
|
|
291
|
+
command,
|
|
292
|
+
arg0,
|
|
293
|
+
arg1,
|
|
294
|
+
payload,
|
|
295
|
+
checksum: this.options.calculateChecksum
|
|
296
|
+
? calculateChecksum(payload)
|
|
297
|
+
: 0,
|
|
298
|
+
magic: command ^ 0xffffffff,
|
|
299
|
+
});
|
|
320
300
|
}
|
|
321
301
|
|
|
322
302
|
public async close() {
|
|
323
303
|
// Send `CLSE` packets for all sockets
|
|
324
304
|
await Promise.all(
|
|
325
|
-
Array.from(this
|
|
305
|
+
Array.from(this.#sockets.values(), (socket) => socket.close())
|
|
326
306
|
);
|
|
327
307
|
|
|
328
308
|
// Stop receiving
|
|
329
309
|
// It's possible that we haven't received all `CLSE` confirm packets,
|
|
330
310
|
// but it doesn't matter, the next connection can cope with them.
|
|
331
|
-
this
|
|
332
|
-
this.
|
|
333
|
-
this.
|
|
311
|
+
this.#closed = true;
|
|
312
|
+
this.#readAbortController.abort();
|
|
313
|
+
this.#writer.releaseLock();
|
|
334
314
|
|
|
335
315
|
// `pipe().then()` will call `dispose`
|
|
336
316
|
}
|
|
337
317
|
|
|
338
318
|
private dispose() {
|
|
339
|
-
for (const socket of this
|
|
340
|
-
socket.dispose().catch(
|
|
341
|
-
void e;
|
|
342
|
-
});
|
|
319
|
+
for (const socket of this.#sockets.values()) {
|
|
320
|
+
socket.dispose().catch(unreachable);
|
|
343
321
|
}
|
|
344
322
|
|
|
345
|
-
this.
|
|
323
|
+
this.#disconnected.resolve();
|
|
346
324
|
}
|
|
347
325
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ConsumableTransformStream } from "@yume-chan/stream-extra";
|
|
2
|
+
import Struct from "@yume-chan/struct";
|
|
3
|
+
|
|
4
|
+
export enum AdbCommand {
|
|
5
|
+
Auth = 0x48545541, // 'AUTH'
|
|
6
|
+
Close = 0x45534c43, // 'CLSE'
|
|
7
|
+
Connect = 0x4e584e43, // 'CNXN'
|
|
8
|
+
OK = 0x59414b4f, // 'OKAY'
|
|
9
|
+
Open = 0x4e45504f, // 'OPEN'
|
|
10
|
+
Write = 0x45545257, // 'WRTE'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const AdbPacketHeader = new Struct({ littleEndian: true })
|
|
14
|
+
.uint32("command")
|
|
15
|
+
.uint32("arg0")
|
|
16
|
+
.uint32("arg1")
|
|
17
|
+
.uint32("payloadLength")
|
|
18
|
+
.uint32("checksum")
|
|
19
|
+
.int32("magic");
|
|
20
|
+
|
|
21
|
+
export type AdbPacketHeader = (typeof AdbPacketHeader)["TDeserializeResult"];
|
|
22
|
+
|
|
23
|
+
type AdbPacketHeaderInit = (typeof AdbPacketHeader)["TInit"];
|
|
24
|
+
|
|
25
|
+
export const AdbPacket = new Struct({ littleEndian: true })
|
|
26
|
+
.concat(AdbPacketHeader)
|
|
27
|
+
.uint8Array("payload", { lengthField: "payloadLength" });
|
|
28
|
+
|
|
29
|
+
export type AdbPacket = (typeof AdbPacket)["TDeserializeResult"];
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* `AdbPacketData` contains all the useful fields of `AdbPacket`.
|
|
33
|
+
*
|
|
34
|
+
* `AdvDaemonConnection#connect` will return a `ReadableStream<AdbPacketData>`,
|
|
35
|
+
* allow each connection to encode `AdbPacket` in different methods.
|
|
36
|
+
*
|
|
37
|
+
* `AdbDaemonConnection#connect` will return a `WritableStream<AdbPacketInit>`,
|
|
38
|
+
* however, `AdbDaemonTransport` will transform `AdbPacketData` to `AdbPacketInit` for you,
|
|
39
|
+
* so `AdbSocket#writable#write` only needs `AdbPacketData`.
|
|
40
|
+
*/
|
|
41
|
+
export type AdbPacketData = Omit<
|
|
42
|
+
(typeof AdbPacket)["TInit"],
|
|
43
|
+
"checksum" | "magic"
|
|
44
|
+
>;
|
|
45
|
+
|
|
46
|
+
export type AdbPacketInit = (typeof AdbPacket)["TInit"];
|
|
47
|
+
|
|
48
|
+
export function calculateChecksum(payload: Uint8Array): number {
|
|
49
|
+
return payload.reduce((result, item) => result + item, 0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class AdbPacketSerializeStream extends ConsumableTransformStream<
|
|
53
|
+
AdbPacketInit,
|
|
54
|
+
Uint8Array
|
|
55
|
+
> {
|
|
56
|
+
public constructor() {
|
|
57
|
+
const headerBuffer = new Uint8Array(AdbPacketHeader.size);
|
|
58
|
+
super({
|
|
59
|
+
transform: async (chunk, controller) => {
|
|
60
|
+
const init = chunk as AdbPacketInit & AdbPacketHeaderInit;
|
|
61
|
+
init.payloadLength = init.payload.byteLength;
|
|
62
|
+
|
|
63
|
+
AdbPacketHeader.serialize(init, headerBuffer);
|
|
64
|
+
await controller.enqueue(headerBuffer);
|
|
65
|
+
|
|
66
|
+
if (init.payload.byteLength) {
|
|
67
|
+
// USB protocol preserves packet boundaries,
|
|
68
|
+
// so we must write payload separately as native ADB does,
|
|
69
|
+
// otherwise the read operation on device will fail.
|
|
70
|
+
await controller.enqueue(init.payload);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|