@yume-chan/adb 0.0.23 → 0.0.24
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/LICENSE +1 -1
- package/esm/adb.d.ts +2 -2
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +2 -2
- package/esm/adb.js.map +1 -1
- package/esm/commands/power.d.ts.map +1 -1
- package/esm/commands/power.js +6 -5
- package/esm/commands/power.js.map +1 -1
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +22 -10
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.js +3 -3
- package/esm/commands/subprocess/command.js.map +1 -1
- package/esm/commands/subprocess/protocols/none.d.ts +2 -2
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +3 -3
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +5 -6
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +2 -2
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/list.d.ts +2 -5
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +2 -4
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +1 -4
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +2 -2
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +4 -7
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +3 -6
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.d.ts +13 -18
- package/esm/commands/sync/request.d.ts.map +1 -1
- package/esm/commands/sync/request.js +23 -28
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +18 -12
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +39 -17
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +2 -2
- package/esm/commands/sync/socket.d.ts.map +1 -1
- package/esm/commands/sync/socket.js +10 -5
- package/esm/commands/sync/socket.js.map +1 -1
- package/esm/commands/sync/stat.d.ts +0 -3
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +0 -2
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +4 -3
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +4 -1
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.js +1 -1
- package/esm/commands/tcpip.js.map +1 -1
- package/esm/daemon/auth.js +1 -1
- package/esm/daemon/auth.js.map +1 -1
- package/esm/daemon/crypto.d.ts +3 -2
- package/esm/daemon/crypto.d.ts.map +1 -1
- package/esm/daemon/crypto.js +56 -49
- package/esm/daemon/crypto.js.map +1 -1
- package/esm/daemon/dispatcher.d.ts +35 -10
- package/esm/daemon/dispatcher.d.ts.map +1 -1
- package/esm/daemon/dispatcher.js +44 -31
- package/esm/daemon/dispatcher.js.map +1 -1
- package/esm/daemon/packet.d.ts +2 -2
- package/esm/daemon/packet.d.ts.map +1 -1
- package/esm/daemon/packet.js +13 -12
- package/esm/daemon/packet.js.map +1 -1
- package/esm/daemon/socket.d.ts +10 -5
- package/esm/daemon/socket.d.ts.map +1 -1
- package/esm/daemon/socket.js +17 -15
- package/esm/daemon/socket.js.map +1 -1
- package/esm/daemon/transport.d.ts +55 -15
- package/esm/daemon/transport.d.ts.map +1 -1
- package/esm/daemon/transport.js +9 -10
- package/esm/daemon/transport.js.map +1 -1
- package/esm/server/client.d.ts +128 -50
- package/esm/server/client.d.ts.map +1 -1
- package/esm/server/client.js +325 -124
- package/esm/server/client.js.map +1 -1
- package/esm/server/transport.js +4 -4
- package/esm/server/transport.js.map +1 -1
- package/esm/utils/base64.d.ts.map +1 -1
- package/esm/utils/base64.js +33 -22
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/hex.d.ts +1 -1
- package/esm/utils/hex.d.ts.map +1 -1
- package/esm/utils/hex.js +12 -14
- package/esm/utils/hex.js.map +1 -1
- package/esm/utils/index.d.ts +1 -1
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +1 -1
- package/esm/utils/index.js.map +1 -1
- package/esm/utils/sequence-equal.d.ts +2 -0
- package/esm/utils/sequence-equal.d.ts.map +1 -0
- package/esm/utils/sequence-equal.js +12 -0
- package/esm/utils/sequence-equal.js.map +1 -0
- package/package.json +12 -14
- package/src/adb.ts +7 -4
- package/src/commands/power.ts +7 -5
- package/src/commands/reverse.ts +30 -17
- package/src/commands/subprocess/command.ts +3 -3
- package/src/commands/subprocess/protocols/none.ts +2 -2
- package/src/commands/subprocess/protocols/shell.ts +7 -11
- package/src/commands/subprocess/protocols/types.ts +2 -2
- package/src/commands/sync/list.ts +2 -4
- package/src/commands/sync/pull.ts +2 -2
- package/src/commands/sync/push.ts +7 -10
- package/src/commands/sync/request.ts +32 -32
- package/src/commands/sync/response.ts +47 -20
- package/src/commands/sync/socket.ts +13 -8
- package/src/commands/sync/stat.ts +0 -2
- package/src/commands/sync/sync.ts +8 -3
- package/src/commands/tcpip.ts +1 -1
- package/src/daemon/auth.ts +1 -1
- package/src/daemon/crypto.ts +64 -55
- package/src/daemon/dispatcher.ts +104 -42
- package/src/daemon/packet.ts +21 -14
- package/src/daemon/socket.ts +28 -25
- package/src/daemon/transport.ts +71 -24
- package/src/server/client.ts +420 -208
- package/src/server/transport.ts +4 -4
- package/src/utils/base64.ts +33 -22
- package/src/utils/hex.ts +16 -14
- package/src/utils/index.ts +1 -1
- package/src/utils/sequence-equal.ts +13 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/utils/conditional-variable.d.ts +0 -8
- package/esm/utils/conditional-variable.d.ts.map +0 -1
- package/esm/utils/conditional-variable.js +0 -34
- package/esm/utils/conditional-variable.js.map +0 -1
- package/src/utils/conditional-variable.ts +0 -45
package/src/daemon/socket.ts
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import { PromiseResolver } from "@yume-chan/async";
|
|
2
2
|
import type { Disposable } from "@yume-chan/event";
|
|
3
3
|
import type {
|
|
4
|
-
AbortSignal,
|
|
5
|
-
Consumable,
|
|
6
4
|
PushReadableStreamController,
|
|
7
5
|
ReadableStream,
|
|
8
6
|
WritableStream,
|
|
9
7
|
WritableStreamDefaultController,
|
|
10
8
|
} from "@yume-chan/stream-extra";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
PushReadableStream,
|
|
14
|
-
} from "@yume-chan/stream-extra";
|
|
9
|
+
import { MaybeConsumable, PushReadableStream } from "@yume-chan/stream-extra";
|
|
10
|
+
import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct";
|
|
15
11
|
|
|
16
12
|
import type { AdbSocket } from "../adb.js";
|
|
17
13
|
|
|
@@ -26,11 +22,15 @@ export interface AdbDaemonSocketInfo {
|
|
|
26
22
|
service: string;
|
|
27
23
|
}
|
|
28
24
|
|
|
29
|
-
export interface
|
|
30
|
-
extends AdbDaemonSocketInfo {
|
|
25
|
+
export interface AdbDaemonSocketInit extends AdbDaemonSocketInfo {
|
|
31
26
|
dispatcher: AdbPacketDispatcher;
|
|
32
27
|
|
|
33
28
|
highWaterMark?: number | undefined;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The initial delayed ack byte count, or `Infinity` if delayed ack is disabled.
|
|
32
|
+
*/
|
|
33
|
+
availableWriteBytes: number;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export class AdbDaemonSocketController
|
|
@@ -50,7 +50,7 @@ export class AdbDaemonSocketController
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
#writableController!: WritableStreamDefaultController;
|
|
53
|
-
readonly writable: WritableStream<
|
|
53
|
+
readonly writable: WritableStream<MaybeConsumable<Uint8Array>>;
|
|
54
54
|
|
|
55
55
|
#closed = false;
|
|
56
56
|
|
|
@@ -66,16 +66,16 @@ export class AdbDaemonSocketController
|
|
|
66
66
|
|
|
67
67
|
#availableWriteBytesChanged: PromiseResolver<void> | undefined;
|
|
68
68
|
/**
|
|
69
|
-
* When delayed ack is disabled,
|
|
70
|
-
*
|
|
71
|
-
* is waiting for ack.
|
|
69
|
+
* When delayed ack is disabled, returns `Infinity` if the socket is ready to write
|
|
70
|
+
* (exactly one packet can be written no matter how large it is), or `-1` if the socket
|
|
71
|
+
* is waiting for ack message.
|
|
72
72
|
*
|
|
73
|
-
* When delayed ack is enabled, a non-negative finite number indicates the number of
|
|
74
|
-
* bytes that can be written to the socket before
|
|
73
|
+
* When delayed ack is enabled, returns a non-negative finite number indicates the number of
|
|
74
|
+
* bytes that can be written to the socket before waiting for ack message.
|
|
75
75
|
*/
|
|
76
76
|
#availableWriteBytes = 0;
|
|
77
77
|
|
|
78
|
-
constructor(options:
|
|
78
|
+
constructor(options: AdbDaemonSocketInit) {
|
|
79
79
|
this.#dispatcher = options.dispatcher;
|
|
80
80
|
this.localId = options.localId;
|
|
81
81
|
this.remoteId = options.remoteId;
|
|
@@ -86,11 +86,16 @@ export class AdbDaemonSocketController
|
|
|
86
86
|
this.#readableController = controller;
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
this.writable = new
|
|
89
|
+
this.writable = new MaybeConsumable.WritableStream<Uint8Array>({
|
|
90
90
|
start: (controller) => {
|
|
91
91
|
this.#writableController = controller;
|
|
92
|
+
controller.signal.addEventListener("abort", () => {
|
|
93
|
+
this.#availableWriteBytesChanged?.reject(
|
|
94
|
+
controller.signal.reason,
|
|
95
|
+
);
|
|
96
|
+
});
|
|
92
97
|
},
|
|
93
|
-
write: async (data
|
|
98
|
+
write: async (data) => {
|
|
94
99
|
const size = data.length;
|
|
95
100
|
const chunkSize = this.#dispatcher.options.maxPayloadSize;
|
|
96
101
|
for (
|
|
@@ -99,24 +104,21 @@ export class AdbDaemonSocketController
|
|
|
99
104
|
start = end, end += chunkSize
|
|
100
105
|
) {
|
|
101
106
|
const chunk = data.subarray(start, end);
|
|
102
|
-
await this.#writeChunk(chunk
|
|
107
|
+
await this.#writeChunk(chunk);
|
|
103
108
|
}
|
|
104
109
|
},
|
|
105
110
|
});
|
|
106
111
|
|
|
107
112
|
this.#socket = new AdbDaemonSocket(this);
|
|
113
|
+
this.#availableWriteBytes = options.availableWriteBytes;
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
async #writeChunk(data: Uint8Array
|
|
111
|
-
const length = data.
|
|
116
|
+
async #writeChunk(data: Uint8Array) {
|
|
117
|
+
const length = data.length;
|
|
112
118
|
while (this.#availableWriteBytes < length) {
|
|
113
119
|
// Only one lock is required because Web Streams API guarantees
|
|
114
120
|
// that `write` is not reentrant.
|
|
115
121
|
const resolver = new PromiseResolver<void>();
|
|
116
|
-
signal.addEventListener("abort", () => {
|
|
117
|
-
resolver.reject(signal.reason);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
122
|
this.#availableWriteBytesChanged = resolver;
|
|
121
123
|
await resolver.promise;
|
|
122
124
|
}
|
|
@@ -175,6 +177,7 @@ export class AdbDaemonSocketController
|
|
|
175
177
|
AdbCommand.Close,
|
|
176
178
|
this.localId,
|
|
177
179
|
this.remoteId,
|
|
180
|
+
EMPTY_UINT8_ARRAY,
|
|
178
181
|
);
|
|
179
182
|
}
|
|
180
183
|
|
|
@@ -216,7 +219,7 @@ export class AdbDaemonSocket implements AdbDaemonSocketInfo, AdbSocket {
|
|
|
216
219
|
get readable(): ReadableStream<Uint8Array> {
|
|
217
220
|
return this.#controller.readable;
|
|
218
221
|
}
|
|
219
|
-
get writable(): WritableStream<
|
|
222
|
+
get writable(): WritableStream<MaybeConsumable<Uint8Array>> {
|
|
220
223
|
return this.#controller.writable;
|
|
221
224
|
}
|
|
222
225
|
|
package/src/daemon/transport.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { PromiseResolver } from "@yume-chan/async";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ReadableWritablePair } from "@yume-chan/stream-extra";
|
|
3
3
|
import {
|
|
4
4
|
AbortController,
|
|
5
|
-
|
|
5
|
+
Consumable,
|
|
6
6
|
WritableStream,
|
|
7
7
|
} from "@yume-chan/stream-extra";
|
|
8
8
|
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
@@ -56,26 +56,52 @@ export type AdbDaemonConnection = ReadableWritablePair<
|
|
|
56
56
|
Consumable<AdbPacketInit>
|
|
57
57
|
>;
|
|
58
58
|
|
|
59
|
-
interface AdbDaemonAuthenticationOptions {
|
|
59
|
+
export interface AdbDaemonAuthenticationOptions {
|
|
60
60
|
serial: string;
|
|
61
61
|
connection: AdbDaemonConnection;
|
|
62
62
|
credentialStore: AdbCredentialStore;
|
|
63
63
|
authenticators?: AdbAuthenticator[];
|
|
64
64
|
features?: readonly AdbFeature[];
|
|
65
|
+
|
|
65
66
|
/**
|
|
66
67
|
* The number of bytes the device can send before receiving an ack packet.
|
|
68
|
+
* Using delayed ack can improve the throughput,
|
|
69
|
+
* especially when the device is connected over Wi-Fi (so the latency is higher).
|
|
67
70
|
*
|
|
68
71
|
* Set to 0 or any negative value to disable delayed ack in handshake.
|
|
69
72
|
* Otherwise the value must be in the range of unsigned 32-bit integer.
|
|
70
73
|
*
|
|
71
|
-
* Delayed ack
|
|
74
|
+
* Delayed ack was added in Android 14,
|
|
75
|
+
* this option will be ignored when the device doesn't support it.
|
|
76
|
+
*
|
|
77
|
+
* @default ADB_DAEMON_DEFAULT_INITIAL_PAYLOAD_SIZE
|
|
72
78
|
*/
|
|
73
79
|
initialDelayedAckBytes?: number;
|
|
80
|
+
|
|
74
81
|
/**
|
|
75
|
-
* Whether to
|
|
82
|
+
* Whether to keep the `connection` open (don't call `writable.close` and `readable.cancel`)
|
|
83
|
+
* when `AdbDaemonTransport.close` is called.
|
|
84
|
+
*
|
|
85
|
+
* Note that when `authenticate` fails,
|
|
86
|
+
* no matter which value this option has,
|
|
87
|
+
* the `connection` is always kept open, so it can be used in another `authenticate` call.
|
|
88
|
+
*
|
|
89
|
+
* @default false
|
|
76
90
|
*/
|
|
77
91
|
preserveConnection?: boolean | undefined;
|
|
78
|
-
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* When set, the transport will throw an error when
|
|
95
|
+
* one of the socket readable stalls for this amount of milliseconds.
|
|
96
|
+
*
|
|
97
|
+
* Because ADB is a multiplexed protocol, blocking one socket will also block all other sockets.
|
|
98
|
+
* It's important to always read from all sockets to prevent stalling.
|
|
99
|
+
*
|
|
100
|
+
* This option is helpful to detect bugs in the client code.
|
|
101
|
+
*
|
|
102
|
+
* @default undefined
|
|
103
|
+
*/
|
|
104
|
+
readTimeLimit?: number | undefined;
|
|
79
105
|
}
|
|
80
106
|
|
|
81
107
|
interface AdbDaemonSocketConnectorConstructionOptions {
|
|
@@ -85,20 +111,39 @@ interface AdbDaemonSocketConnectorConstructionOptions {
|
|
|
85
111
|
maxPayloadSize: number;
|
|
86
112
|
banner: string;
|
|
87
113
|
features?: readonly AdbFeature[];
|
|
114
|
+
|
|
88
115
|
/**
|
|
89
116
|
* The number of bytes the device can send before receiving an ack packet.
|
|
117
|
+
* Using delayed ack can improve the throughput,
|
|
118
|
+
* especially when the device is connected over Wi-Fi (so the latency is higher).
|
|
90
119
|
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
120
|
+
* When `features` doesn't include `AdbFeature.DelayedAck`, it must be set to 0. Otherwise,
|
|
121
|
+
* the value must be in the range of unsigned 32-bit integer. If the device enabled
|
|
122
|
+
* delayed ack but the client didn't, the device will throw an error when the client sends
|
|
123
|
+
* the first data packet. And vice versa.
|
|
95
124
|
*/
|
|
96
|
-
initialDelayedAckBytes
|
|
125
|
+
initialDelayedAckBytes: number;
|
|
126
|
+
|
|
97
127
|
/**
|
|
98
|
-
* Whether to
|
|
128
|
+
* Whether to keep the `connection` open (don't call `writable.close` and `readable.cancel`)
|
|
129
|
+
* when `AdbDaemonTransport.close` is called.
|
|
130
|
+
*
|
|
131
|
+
* @default false
|
|
99
132
|
*/
|
|
100
133
|
preserveConnection?: boolean | undefined;
|
|
101
|
-
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* When set, the transport will throw an error when
|
|
137
|
+
* one of the socket readable stalls for this amount of milliseconds.
|
|
138
|
+
*
|
|
139
|
+
* Because ADB is a multiplexed protocol, blocking one socket will also block all other sockets.
|
|
140
|
+
* It's important to always read from all sockets to prevent stalling.
|
|
141
|
+
*
|
|
142
|
+
* This option is helpful to detect bugs in the client code.
|
|
143
|
+
*
|
|
144
|
+
* @default undefined
|
|
145
|
+
*/
|
|
146
|
+
readTimeLimit?: number | undefined;
|
|
102
147
|
}
|
|
103
148
|
|
|
104
149
|
export class AdbDaemonTransport implements AdbTransport {
|
|
@@ -106,9 +151,9 @@ export class AdbDaemonTransport implements AdbTransport {
|
|
|
106
151
|
* Authenticates the connection and creates an `AdbDaemonTransport` instance
|
|
107
152
|
* that can be used by `Adb` class.
|
|
108
153
|
*
|
|
109
|
-
* If an authentication process failed,
|
|
110
|
-
*
|
|
111
|
-
*
|
|
154
|
+
* If an authentication process failed,
|
|
155
|
+
* no matter which value the `preserveConnection` option has,
|
|
156
|
+
* the `connection` is always kept open, so it can be used in another `authenticate` call.
|
|
112
157
|
*/
|
|
113
158
|
static async authenticate({
|
|
114
159
|
serial,
|
|
@@ -170,11 +215,10 @@ export class AdbDaemonTransport implements AdbTransport {
|
|
|
170
215
|
)
|
|
171
216
|
.then(
|
|
172
217
|
() => {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
218
|
+
// If `resolver` is already settled, call `reject` won't do anything.
|
|
219
|
+
resolver.reject(
|
|
220
|
+
new Error("Connection closed unexpectedly"),
|
|
221
|
+
);
|
|
178
222
|
},
|
|
179
223
|
(e) => {
|
|
180
224
|
resolver.reject(e);
|
|
@@ -187,7 +231,10 @@ export class AdbDaemonTransport implements AdbTransport {
|
|
|
187
231
|
// Because we don't know if the device needs it or not.
|
|
188
232
|
(init as AdbPacketInit).checksum = calculateChecksum(init.payload);
|
|
189
233
|
(init as AdbPacketInit).magic = init.command ^ 0xffffffff;
|
|
190
|
-
await
|
|
234
|
+
await Consumable.WritableStream.write(
|
|
235
|
+
writer,
|
|
236
|
+
init as AdbPacketInit,
|
|
237
|
+
);
|
|
191
238
|
}
|
|
192
239
|
|
|
193
240
|
const actualFeatures = features.slice();
|
|
@@ -275,7 +322,7 @@ export class AdbDaemonTransport implements AdbTransport {
|
|
|
275
322
|
version,
|
|
276
323
|
banner,
|
|
277
324
|
features = ADB_DAEMON_DEFAULT_FEATURES,
|
|
278
|
-
initialDelayedAckBytes
|
|
325
|
+
initialDelayedAckBytes,
|
|
279
326
|
...options
|
|
280
327
|
}: AdbDaemonSocketConnectorConstructionOptions) {
|
|
281
328
|
this.#serial = serial;
|
|
@@ -285,7 +332,7 @@ export class AdbDaemonTransport implements AdbTransport {
|
|
|
285
332
|
|
|
286
333
|
if (features.includes(AdbFeature.DelayedAck)) {
|
|
287
334
|
if (initialDelayedAckBytes <= 0) {
|
|
288
|
-
throw new
|
|
335
|
+
throw new TypeError(
|
|
289
336
|
"`initialDelayedAckBytes` must be greater than 0 when DelayedAck feature is enabled.",
|
|
290
337
|
);
|
|
291
338
|
}
|