@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,38 +1,44 @@
|
|
|
1
1
|
import { PromiseResolver } from "@yume-chan/async";
|
|
2
|
-
import {
|
|
2
|
+
import type { Disposable } from "@yume-chan/event";
|
|
3
|
+
import type {
|
|
4
|
+
Consumable,
|
|
5
|
+
PushReadableStreamController,
|
|
6
|
+
ReadableStream,
|
|
7
|
+
ReadableWritablePair,
|
|
8
|
+
WritableStream,
|
|
9
|
+
} from "@yume-chan/stream-extra";
|
|
3
10
|
import {
|
|
4
|
-
|
|
11
|
+
ConsumableWritableStream,
|
|
12
|
+
DistributionStream,
|
|
5
13
|
DuplexStreamFactory,
|
|
6
14
|
PushReadableStream,
|
|
7
|
-
WritableStream,
|
|
8
15
|
pipeFrom,
|
|
9
|
-
type PushReadableStreamController,
|
|
10
|
-
type ReadableStream,
|
|
11
|
-
type ReadableWritablePair,
|
|
12
16
|
} from "@yume-chan/stream-extra";
|
|
13
17
|
|
|
14
|
-
import {
|
|
18
|
+
import type { Closeable } from "../adb.js";
|
|
15
19
|
|
|
16
|
-
import {
|
|
20
|
+
import type { AdbPacketDispatcher } from "./dispatcher.js";
|
|
21
|
+
import { AdbCommand } from "./packet.js";
|
|
17
22
|
|
|
18
|
-
export interface
|
|
23
|
+
export interface AdbDaemonSocketInfo {
|
|
19
24
|
localId: number;
|
|
20
25
|
remoteId: number;
|
|
21
26
|
|
|
22
27
|
localCreated: boolean;
|
|
23
|
-
|
|
28
|
+
service: string;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
|
-
export interface
|
|
31
|
+
export interface AdbDaemonSocketConstructionOptions
|
|
32
|
+
extends AdbDaemonSocketInfo {
|
|
27
33
|
dispatcher: AdbPacketDispatcher;
|
|
28
34
|
|
|
29
35
|
highWaterMark?: number | undefined;
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
export class
|
|
38
|
+
export class AdbDaemonSocketController
|
|
33
39
|
implements
|
|
34
|
-
|
|
35
|
-
ReadableWritablePair<Uint8Array, Uint8Array
|
|
40
|
+
AdbDaemonSocketInfo,
|
|
41
|
+
ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>,
|
|
36
42
|
Closeable,
|
|
37
43
|
Disposable
|
|
38
44
|
{
|
|
@@ -41,44 +47,47 @@ export class AdbSocketController
|
|
|
41
47
|
public readonly localId!: number;
|
|
42
48
|
public readonly remoteId!: number;
|
|
43
49
|
public readonly localCreated!: boolean;
|
|
44
|
-
public readonly
|
|
50
|
+
public readonly service!: string;
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
#duplex: DuplexStreamFactory<Uint8Array, Consumable<Uint8Array>>;
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
#readable: ReadableStream<Uint8Array>;
|
|
55
|
+
#readableController!: PushReadableStreamController<Uint8Array>;
|
|
50
56
|
public get readable() {
|
|
51
|
-
return this
|
|
57
|
+
return this.#readable;
|
|
52
58
|
}
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
public readonly writable: WritableStream<Uint8Array
|
|
60
|
+
#writePromise: PromiseResolver<void> | undefined;
|
|
61
|
+
public readonly writable: WritableStream<Consumable<Uint8Array>>;
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
#closed = false;
|
|
58
64
|
/**
|
|
59
65
|
* Whether the socket is half-closed (i.e. the local side initiated the close).
|
|
60
66
|
*
|
|
61
67
|
* It's only used by dispatcher to avoid sending another `CLSE` packet to remote.
|
|
62
68
|
*/
|
|
63
69
|
public get closed() {
|
|
64
|
-
return this
|
|
70
|
+
return this.#closed;
|
|
65
71
|
}
|
|
66
72
|
|
|
67
|
-
private _socket:
|
|
73
|
+
private _socket: AdbDaemonSocket;
|
|
68
74
|
public get socket() {
|
|
69
75
|
return this._socket;
|
|
70
76
|
}
|
|
71
77
|
|
|
72
|
-
public constructor(options:
|
|
78
|
+
public constructor(options: AdbDaemonSocketConstructionOptions) {
|
|
73
79
|
Object.assign(this, options);
|
|
74
80
|
|
|
75
81
|
// Check this image to help you understand the stream graph
|
|
76
82
|
// cspell: disable-next-line
|
|
77
83
|
// https://www.plantuml.com/plantuml/png/TL0zoeGm4ErpYc3l5JxyS0yWM6mX5j4C6p4cxcJ25ejttuGX88ZftizxUKmJI275pGhXl0PP_UkfK_CAz5Z2hcWsW9Ny2fdU4C1f5aSchFVxA8vJjlTPRhqZzDQMRB7AklwJ0xXtX0ZSKH1h24ghoKAdGY23FhxC4nS2pDvxzIvxb-8THU0XlEQJ-ZB7SnXTAvc_LhOckhMdLBnbtndpb-SB7a8q2SRD_W00
|
|
78
84
|
|
|
79
|
-
this
|
|
85
|
+
this.#duplex = new DuplexStreamFactory<
|
|
86
|
+
Uint8Array,
|
|
87
|
+
Consumable<Uint8Array>
|
|
88
|
+
>({
|
|
80
89
|
close: async () => {
|
|
81
|
-
this
|
|
90
|
+
this.#closed = true;
|
|
82
91
|
|
|
83
92
|
await this.dispatcher.sendPacket(
|
|
84
93
|
AdbCommand.Close,
|
|
@@ -91,14 +100,14 @@ export class AdbSocketController
|
|
|
91
100
|
},
|
|
92
101
|
dispose: () => {
|
|
93
102
|
// Error out the pending writes
|
|
94
|
-
this
|
|
103
|
+
this.#writePromise?.reject(new Error("Socket closed"));
|
|
95
104
|
},
|
|
96
105
|
});
|
|
97
106
|
|
|
98
|
-
this
|
|
107
|
+
this.#readable = this.#duplex.wrapReadable(
|
|
99
108
|
new PushReadableStream(
|
|
100
109
|
(controller) => {
|
|
101
|
-
this
|
|
110
|
+
this.#readableController = controller;
|
|
102
111
|
},
|
|
103
112
|
{
|
|
104
113
|
highWaterMark: options.highWaterMark ?? 16 * 1024,
|
|
@@ -110,47 +119,47 @@ export class AdbSocketController
|
|
|
110
119
|
);
|
|
111
120
|
|
|
112
121
|
this.writable = pipeFrom(
|
|
113
|
-
this.
|
|
114
|
-
new
|
|
122
|
+
this.#duplex.createWritable(
|
|
123
|
+
new ConsumableWritableStream<Uint8Array>({
|
|
115
124
|
write: async (chunk) => {
|
|
116
125
|
// Wait for an ack packet
|
|
117
|
-
this
|
|
126
|
+
this.#writePromise = new PromiseResolver();
|
|
118
127
|
await this.dispatcher.sendPacket(
|
|
119
128
|
AdbCommand.Write,
|
|
120
129
|
this.localId,
|
|
121
130
|
this.remoteId,
|
|
122
131
|
chunk
|
|
123
132
|
);
|
|
124
|
-
await this.
|
|
133
|
+
await this.#writePromise.promise;
|
|
125
134
|
},
|
|
126
135
|
})
|
|
127
136
|
),
|
|
128
|
-
new
|
|
137
|
+
new DistributionStream(this.dispatcher.options.maxPayloadSize)
|
|
129
138
|
);
|
|
130
139
|
|
|
131
|
-
this._socket = new
|
|
140
|
+
this._socket = new AdbDaemonSocket(this);
|
|
132
141
|
}
|
|
133
142
|
|
|
134
|
-
public async enqueue(
|
|
143
|
+
public async enqueue(data: Uint8Array) {
|
|
135
144
|
// Consumer may abort the `ReadableStream` to close the socket,
|
|
136
145
|
// it's OK to throw away further packets in this case.
|
|
137
|
-
if (this.
|
|
146
|
+
if (this.#readableController.abortSignal.aborted) {
|
|
138
147
|
return;
|
|
139
148
|
}
|
|
140
149
|
|
|
141
|
-
await this.
|
|
150
|
+
await this.#readableController.enqueue(data);
|
|
142
151
|
}
|
|
143
152
|
|
|
144
153
|
public ack() {
|
|
145
|
-
this
|
|
154
|
+
this.#writePromise?.resolve();
|
|
146
155
|
}
|
|
147
156
|
|
|
148
157
|
public async close(): Promise<void> {
|
|
149
|
-
await this.
|
|
158
|
+
await this.#duplex.close();
|
|
150
159
|
}
|
|
151
160
|
|
|
152
161
|
public dispose() {
|
|
153
|
-
return this.
|
|
162
|
+
return this.#duplex.dispose();
|
|
154
163
|
}
|
|
155
164
|
}
|
|
156
165
|
|
|
@@ -162,36 +171,42 @@ export class AdbSocketController
|
|
|
162
171
|
* `socket.writable.abort()`, `socket.writable.getWriter().abort()`,
|
|
163
172
|
* `socket.writable.close()` or `socket.writable.getWriter().close()`.
|
|
164
173
|
*/
|
|
165
|
-
export class
|
|
166
|
-
implements
|
|
174
|
+
export class AdbDaemonSocket
|
|
175
|
+
implements
|
|
176
|
+
AdbDaemonSocketInfo,
|
|
177
|
+
ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>
|
|
167
178
|
{
|
|
168
|
-
|
|
179
|
+
#controller: AdbDaemonSocketController;
|
|
169
180
|
|
|
170
181
|
public get localId(): number {
|
|
171
|
-
return this.
|
|
182
|
+
return this.#controller.localId;
|
|
172
183
|
}
|
|
173
184
|
public get remoteId(): number {
|
|
174
|
-
return this.
|
|
185
|
+
return this.#controller.remoteId;
|
|
175
186
|
}
|
|
176
187
|
public get localCreated(): boolean {
|
|
177
|
-
return this.
|
|
188
|
+
return this.#controller.localCreated;
|
|
178
189
|
}
|
|
179
|
-
public get
|
|
180
|
-
return this.
|
|
190
|
+
public get service(): string {
|
|
191
|
+
return this.#controller.service;
|
|
181
192
|
}
|
|
182
193
|
|
|
183
194
|
public get readable(): ReadableStream<Uint8Array> {
|
|
184
|
-
return this.
|
|
195
|
+
return this.#controller.readable;
|
|
196
|
+
}
|
|
197
|
+
public get writable(): WritableStream<Consumable<Uint8Array>> {
|
|
198
|
+
return this.#controller.writable;
|
|
185
199
|
}
|
|
186
|
-
|
|
187
|
-
|
|
200
|
+
|
|
201
|
+
public get closed(): boolean {
|
|
202
|
+
return this.#controller.closed;
|
|
188
203
|
}
|
|
189
204
|
|
|
190
|
-
public constructor(controller:
|
|
191
|
-
this
|
|
205
|
+
public constructor(controller: AdbDaemonSocketController) {
|
|
206
|
+
this.#controller = controller;
|
|
192
207
|
}
|
|
193
208
|
|
|
194
209
|
public close() {
|
|
195
|
-
return this.
|
|
210
|
+
return this.#controller.close();
|
|
196
211
|
}
|
|
197
212
|
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { PromiseResolver } from "@yume-chan/async";
|
|
2
|
+
import type { Consumable, ReadableWritablePair } from "@yume-chan/stream-extra";
|
|
3
|
+
import {
|
|
4
|
+
AbortController,
|
|
5
|
+
ConsumableWritableStream,
|
|
6
|
+
WritableStream,
|
|
7
|
+
} from "@yume-chan/stream-extra";
|
|
8
|
+
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
9
|
+
import { decodeUtf8, encodeUtf8 } from "@yume-chan/struct";
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
AdbIncomingSocketHandler,
|
|
13
|
+
AdbSocket,
|
|
14
|
+
AdbTransport,
|
|
15
|
+
} from "../adb.js";
|
|
16
|
+
import { AdbBanner } from "../banner.js";
|
|
17
|
+
import { AdbFeature } from "../features.js";
|
|
18
|
+
|
|
19
|
+
import type { AdbAuthenticator, AdbCredentialStore } from "./auth.js";
|
|
20
|
+
import {
|
|
21
|
+
ADB_DEFAULT_AUTHENTICATORS,
|
|
22
|
+
AdbAuthenticationProcessor,
|
|
23
|
+
} from "./auth.js";
|
|
24
|
+
import { AdbPacketDispatcher } from "./dispatcher.js";
|
|
25
|
+
import type { AdbPacketData, AdbPacketInit } from "./packet.js";
|
|
26
|
+
import { AdbCommand, calculateChecksum } from "./packet.js";
|
|
27
|
+
|
|
28
|
+
export const ADB_DAEMON_VERSION_OMIT_CHECKSUM = 0x01000001;
|
|
29
|
+
|
|
30
|
+
interface AdbDaemonAuthenticationOptions {
|
|
31
|
+
serial: string;
|
|
32
|
+
connection: ReadableWritablePair<AdbPacketData, Consumable<AdbPacketInit>>;
|
|
33
|
+
credentialStore: AdbCredentialStore;
|
|
34
|
+
authenticators?: AdbAuthenticator[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface AdbDaemonSocketConnectorConstructionOptions {
|
|
38
|
+
serial: string;
|
|
39
|
+
connection: ReadableWritablePair<AdbPacketData, Consumable<AdbPacketInit>>;
|
|
40
|
+
version: number;
|
|
41
|
+
maxPayloadSize: number;
|
|
42
|
+
banner: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class AdbDaemonTransport implements AdbTransport {
|
|
46
|
+
/**
|
|
47
|
+
* Authenticates the connection and creates an `AdbDaemonTransport` instance
|
|
48
|
+
* that can be used by `Adb` class.
|
|
49
|
+
*
|
|
50
|
+
* If an authentication process failed, it's possible to call `authenticate` again
|
|
51
|
+
* on the same connection. Because every time the device receives a `CNXN` packet,
|
|
52
|
+
* it resets all internal state, and starts a new authentication process.
|
|
53
|
+
*/
|
|
54
|
+
public static async authenticate({
|
|
55
|
+
serial,
|
|
56
|
+
connection,
|
|
57
|
+
credentialStore,
|
|
58
|
+
authenticators = ADB_DEFAULT_AUTHENTICATORS,
|
|
59
|
+
}: AdbDaemonAuthenticationOptions): Promise<AdbDaemonTransport> {
|
|
60
|
+
// Initially, set to highest-supported version and payload size.
|
|
61
|
+
let version = 0x01000001;
|
|
62
|
+
// Android 4: 4K, Android 7: 256K, Android 9: 1M
|
|
63
|
+
let maxPayloadSize = 1024 * 1024;
|
|
64
|
+
|
|
65
|
+
const resolver = new PromiseResolver<string>();
|
|
66
|
+
const authProcessor = new AdbAuthenticationProcessor(
|
|
67
|
+
authenticators,
|
|
68
|
+
credentialStore
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Here is similar to `AdbPacketDispatcher`,
|
|
72
|
+
// But the received packet types and send packet processing are different.
|
|
73
|
+
const abortController = new AbortController();
|
|
74
|
+
const pipe = connection.readable
|
|
75
|
+
.pipeTo(
|
|
76
|
+
new WritableStream({
|
|
77
|
+
async write(packet) {
|
|
78
|
+
switch (packet.command) {
|
|
79
|
+
case AdbCommand.Connect:
|
|
80
|
+
version = Math.min(version, packet.arg0);
|
|
81
|
+
maxPayloadSize = Math.min(
|
|
82
|
+
maxPayloadSize,
|
|
83
|
+
packet.arg1
|
|
84
|
+
);
|
|
85
|
+
resolver.resolve(decodeUtf8(packet.payload));
|
|
86
|
+
break;
|
|
87
|
+
case AdbCommand.Auth: {
|
|
88
|
+
const response = await authProcessor.process(
|
|
89
|
+
packet
|
|
90
|
+
);
|
|
91
|
+
await sendPacket(response);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
default:
|
|
95
|
+
// Maybe the previous ADB client exited without reading all packets,
|
|
96
|
+
// so they are still waiting in OS internal buffer.
|
|
97
|
+
// Just ignore them.
|
|
98
|
+
// Because a `Connect` packet will reset the device,
|
|
99
|
+
// Eventually there will be `Connect` and `Auth` response packets.
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
}),
|
|
104
|
+
{
|
|
105
|
+
// Don't cancel the source ReadableStream on AbortSignal abort.
|
|
106
|
+
preventCancel: true,
|
|
107
|
+
signal: abortController.signal,
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
.then(
|
|
111
|
+
() => {
|
|
112
|
+
if (resolver.state === "running") {
|
|
113
|
+
resolver.reject(
|
|
114
|
+
new Error("Connection closed unexpectedly")
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
(e) => {
|
|
119
|
+
resolver.reject(e);
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const writer = connection.writable.getWriter();
|
|
124
|
+
async function sendPacket(init: AdbPacketData) {
|
|
125
|
+
// Always send checksum in auth steps
|
|
126
|
+
// Because we don't know if the device needs it or not.
|
|
127
|
+
(init as AdbPacketInit).checksum = calculateChecksum(init.payload);
|
|
128
|
+
(init as AdbPacketInit).magic = init.command ^ 0xffffffff;
|
|
129
|
+
await ConsumableWritableStream.write(writer, init as AdbPacketInit);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let banner: string;
|
|
133
|
+
try {
|
|
134
|
+
// https://android.googlesource.com/platform/packages/modules/adb/+/79010dc6d5ca7490c493df800d4421730f5466ca/transport.cpp#1252
|
|
135
|
+
// There are some other feature constants, but some of them are only used by ADB server, not devices (daemons).
|
|
136
|
+
const features = [
|
|
137
|
+
AdbFeature.ShellV2,
|
|
138
|
+
AdbFeature.Cmd,
|
|
139
|
+
AdbFeature.StatV2,
|
|
140
|
+
AdbFeature.ListV2,
|
|
141
|
+
AdbFeature.FixedPushMkdir,
|
|
142
|
+
"apex",
|
|
143
|
+
AdbFeature.Abb,
|
|
144
|
+
// only tells the client the symlink timestamp issue in `adb push --sync` has been fixed.
|
|
145
|
+
// No special handling required.
|
|
146
|
+
"fixed_push_symlink_timestamp",
|
|
147
|
+
AdbFeature.AbbExec,
|
|
148
|
+
"remount_shell",
|
|
149
|
+
"track_app",
|
|
150
|
+
"sendrecv_v2",
|
|
151
|
+
"sendrecv_v2_brotli",
|
|
152
|
+
"sendrecv_v2_lz4",
|
|
153
|
+
"sendrecv_v2_zstd",
|
|
154
|
+
"sendrecv_v2_dry_run_send",
|
|
155
|
+
].join(",");
|
|
156
|
+
|
|
157
|
+
await sendPacket({
|
|
158
|
+
command: AdbCommand.Connect,
|
|
159
|
+
arg0: version,
|
|
160
|
+
arg1: maxPayloadSize,
|
|
161
|
+
// The terminating `;` is required in formal definition
|
|
162
|
+
// But ADB daemon (all versions) can still work without it
|
|
163
|
+
payload: encodeUtf8(`host::features=${features}`),
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
banner = await resolver.promise;
|
|
167
|
+
} finally {
|
|
168
|
+
// When failed, release locks on `connection` so the caller can try again.
|
|
169
|
+
// When success, also release locks so `AdbPacketDispatcher` can use them.
|
|
170
|
+
abortController.abort();
|
|
171
|
+
writer.releaseLock();
|
|
172
|
+
|
|
173
|
+
// Wait until pipe stops (`ReadableStream` lock released)
|
|
174
|
+
await pipe;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return new AdbDaemonTransport({
|
|
178
|
+
serial,
|
|
179
|
+
connection,
|
|
180
|
+
version,
|
|
181
|
+
maxPayloadSize,
|
|
182
|
+
banner,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
readonly #dispatcher: AdbPacketDispatcher;
|
|
187
|
+
|
|
188
|
+
#serial: string;
|
|
189
|
+
public get serial() {
|
|
190
|
+
return this.#serial;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
#protocolVersion: number;
|
|
194
|
+
public get protocolVersion() {
|
|
195
|
+
return this.#protocolVersion;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
#maxPayloadSize: number;
|
|
199
|
+
public get maxPayloadSize() {
|
|
200
|
+
return this.#maxPayloadSize;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
#banner: AdbBanner;
|
|
204
|
+
public get banner() {
|
|
205
|
+
return this.#banner;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public get disconnected() {
|
|
209
|
+
return this.#dispatcher.disconnected;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
public constructor({
|
|
213
|
+
serial,
|
|
214
|
+
connection,
|
|
215
|
+
version,
|
|
216
|
+
maxPayloadSize,
|
|
217
|
+
banner,
|
|
218
|
+
}: AdbDaemonSocketConnectorConstructionOptions) {
|
|
219
|
+
this.#serial = serial;
|
|
220
|
+
this.#banner = AdbBanner.parse(banner);
|
|
221
|
+
|
|
222
|
+
let calculateChecksum: boolean;
|
|
223
|
+
let appendNullToServiceString: boolean;
|
|
224
|
+
if (version >= ADB_DAEMON_VERSION_OMIT_CHECKSUM) {
|
|
225
|
+
calculateChecksum = false;
|
|
226
|
+
appendNullToServiceString = false;
|
|
227
|
+
} else {
|
|
228
|
+
calculateChecksum = true;
|
|
229
|
+
appendNullToServiceString = true;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this.#dispatcher = new AdbPacketDispatcher(connection, {
|
|
233
|
+
calculateChecksum,
|
|
234
|
+
appendNullToServiceString,
|
|
235
|
+
maxPayloadSize,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
this.#protocolVersion = version;
|
|
239
|
+
this.#maxPayloadSize = maxPayloadSize;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
public connect(service: string): ValueOrPromise<AdbSocket> {
|
|
243
|
+
return this.#dispatcher.createSocket(service);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public addReverseTunnel(
|
|
247
|
+
handler: AdbIncomingSocketHandler,
|
|
248
|
+
address?: string
|
|
249
|
+
): string {
|
|
250
|
+
if (!address) {
|
|
251
|
+
const id = Math.random().toString().substring(2);
|
|
252
|
+
address = `localabstract:reverse_${id}`;
|
|
253
|
+
}
|
|
254
|
+
this.#dispatcher.addReverseTunnel(address, handler);
|
|
255
|
+
return address;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
public removeReverseTunnel(address: string): void {
|
|
259
|
+
this.#dispatcher.removeReverseTunnel(address);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
public clearReverseTunnels(): void {
|
|
263
|
+
this.#dispatcher.clearReverseTunnels();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
public close(): ValueOrPromise<void> {
|
|
267
|
+
return this.#dispatcher.close();
|
|
268
|
+
}
|
|
269
|
+
}
|
package/src/features.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// The order follows
|
|
2
2
|
// https://android.googlesource.com/platform/packages/modules/adb/+/79010dc6d5ca7490c493df800d4421730f5466ca/transport.cpp#1252
|
|
3
|
-
export enum
|
|
4
|
-
ShellV2 =
|
|
5
|
-
Cmd =
|
|
6
|
-
StatV2 =
|
|
7
|
-
ListV2 =
|
|
8
|
-
FixedPushMkdir =
|
|
3
|
+
export enum AdbFeature {
|
|
4
|
+
ShellV2 = "shell_v2",
|
|
5
|
+
Cmd = "cmd",
|
|
6
|
+
StatV2 = "stat_v2",
|
|
7
|
+
ListV2 = "ls_v2",
|
|
8
|
+
FixedPushMkdir = "fixed_push_mkdir",
|
|
9
|
+
Abb = "abb",
|
|
10
|
+
AbbExec = "abb_exec",
|
|
11
|
+
SendReceiveV2 = "sendrecv_v2",
|
|
9
12
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
export * from "./adb.js";
|
|
2
|
-
export * from "./
|
|
3
|
-
export * from "./backend.js";
|
|
2
|
+
export * from "./banner.js";
|
|
4
3
|
export * from "./commands/index.js";
|
|
5
|
-
export * from "./
|
|
4
|
+
export * from "./daemon/index.js";
|
|
6
5
|
export * from "./features.js";
|
|
7
|
-
export * from "./
|
|
8
|
-
export * from "./socket/index.js";
|
|
6
|
+
export * from "./server/index.js";
|
|
9
7
|
export * from "./utils/index.js";
|