@yume-chan/adb 0.0.19 → 0.0.21
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 +57 -0
- package/CHANGELOG.md +26 -1
- package/README.md +222 -103
- package/esm/adb.d.ts +28 -45
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +34 -213
- 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.map +1 -1
- package/esm/commands/base.js.map +1 -1
- package/esm/commands/framebuffer.d.ts +9 -0
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +27 -3
- package/esm/commands/framebuffer.js.map +1 -1
- package/esm/commands/power.d.ts +1 -1
- package/esm/commands/power.d.ts.map +1 -1
- package/esm/commands/power.js +2 -2
- package/esm/commands/power.js.map +1 -1
- 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/command.d.ts +1 -1
- package/esm/commands/subprocess/command.d.ts.map +1 -1
- package/esm/commands/subprocess/command.js +15 -13
- package/esm/commands/subprocess/command.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 +63 -57
- 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 +9 -9
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.js +2 -2
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +5 -3
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +7 -5
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +8 -14
- package/esm/commands/sync/socket.d.ts.map +1 -1
- package/esm/commands/sync/socket.js +35 -32
- package/esm/commands/sync/socket.js.map +1 -1
- package/esm/commands/sync/stat.js +4 -4
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +26 -18
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +36 -25
- 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} +12 -11
- package/esm/daemon/auth.d.ts.map +1 -0
- package/esm/{auth.js → daemon/auth.js} +31 -22
- package/esm/daemon/auth.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} +24 -28
- 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 +12 -30
- package/esm/daemon/dispatcher.d.ts.map +1 -0
- package/esm/{socket → daemon}/dispatcher.js +80 -78
- 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} +2 -2
- package/esm/{packet.js.map → daemon/packet.js.map} +1 -1
- package/esm/{socket → daemon}/socket.d.ts +15 -19
- package/esm/daemon/socket.d.ts.map +1 -0
- package/esm/{socket → daemon}/socket.js +49 -42
- package/esm/daemon/socket.js.map +1 -0
- package/esm/daemon/transport.d.ts +53 -0
- package/esm/daemon/transport.d.ts.map +1 -0
- package/esm/daemon/transport.js +186 -0
- package/esm/daemon/transport.js.map +1 -0
- package/esm/features.js +1 -1
- package/esm/features.js.map +1 -1
- 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 +328 -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 +12 -12
- package/src/adb.ts +75 -274
- package/src/banner.ts +82 -0
- package/src/commands/base.ts +1 -1
- package/src/commands/framebuffer.ts +31 -3
- package/src/commands/power.ts +10 -10
- package/src/commands/reverse.ts +77 -82
- package/src/commands/subprocess/command.ts +24 -25
- package/src/commands/subprocess/protocols/none.ts +29 -30
- package/src/commands/subprocess/protocols/shell.ts +87 -89
- package/src/commands/subprocess/protocols/types.ts +1 -2
- package/src/commands/sync/list.ts +7 -7
- package/src/commands/sync/pull.ts +4 -4
- package/src/commands/sync/push.ts +28 -16
- package/src/commands/sync/request.ts +4 -4
- package/src/commands/sync/response.ts +13 -11
- package/src/commands/sync/socket.ts +48 -46
- package/src/commands/sync/stat.ts +5 -5
- package/src/commands/sync/sync.ts +55 -43
- package/src/commands/tcpip.ts +6 -4
- package/src/{auth.ts → daemon/auth.ts} +62 -43
- package/src/{crypto.ts → daemon/crypto.ts} +33 -41
- package/src/{backend.ts → daemon/device.ts} +1 -1
- package/src/{socket → daemon}/dispatcher.ts +103 -109
- package/src/daemon/index.ts +7 -0
- package/src/{packet.ts → daemon/packet.ts} +6 -6
- package/src/{socket → daemon}/socket.ts +77 -67
- package/src/daemon/transport.ts +281 -0
- package/src/index.ts +3 -5
- package/src/server/client.ts +473 -0
- package/src/server/index.ts +2 -0
- package/src/server/transport.ts +77 -0
- package/src/utils/auto-reset-event.ts +16 -16
- package/src/utils/base64.ts +5 -5
- package/src/utils/conditional-variable.ts +14 -14
- 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/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
|
@@ -10,16 +10,14 @@ import {
|
|
|
10
10
|
ConsumableWritableStream,
|
|
11
11
|
PushReadableStream,
|
|
12
12
|
StructDeserializeStream,
|
|
13
|
-
TransformStream,
|
|
14
13
|
WritableStream,
|
|
15
14
|
pipeFrom,
|
|
16
15
|
} from "@yume-chan/stream-extra";
|
|
17
16
|
import type { StructValueType } from "@yume-chan/struct";
|
|
18
17
|
import Struct, { placeholder } from "@yume-chan/struct";
|
|
19
18
|
|
|
20
|
-
import type { Adb } from "../../../adb.js";
|
|
19
|
+
import type { Adb, AdbSocket } from "../../../adb.js";
|
|
21
20
|
import { AdbFeature } from "../../../features.js";
|
|
22
|
-
import type { AdbSocket } from "../../../socket/index.js";
|
|
23
21
|
import { encodeUtf8 } from "../../../utils/index.js";
|
|
24
22
|
|
|
25
23
|
import type { AdbSubprocessProtocol } from "./types.js";
|
|
@@ -62,54 +60,39 @@ class StdinSerializeStream extends ConsumableTransformStream<
|
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
class StdoutDeserializeStream extends TransformStream<
|
|
66
|
-
AdbShellProtocolPacket,
|
|
67
|
-
Uint8Array
|
|
68
|
-
> {
|
|
69
|
-
constructor(type: AdbShellProtocolId.Stdout | AdbShellProtocolId.Stderr) {
|
|
70
|
-
super({
|
|
71
|
-
transform(chunk, controller) {
|
|
72
|
-
if (chunk.id === type) {
|
|
73
|
-
controller.enqueue(chunk.data);
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
63
|
class MultiplexStream<T> {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return this
|
|
64
|
+
#readable: PushReadableStream<T>;
|
|
65
|
+
#readableController!: PushReadableStreamController<T>;
|
|
66
|
+
get readable() {
|
|
67
|
+
return this.#readable;
|
|
85
68
|
}
|
|
86
69
|
|
|
87
|
-
|
|
70
|
+
#activeCount = 0;
|
|
88
71
|
|
|
89
72
|
constructor() {
|
|
90
|
-
this
|
|
91
|
-
this
|
|
73
|
+
this.#readable = new PushReadableStream((controller) => {
|
|
74
|
+
this.#readableController = controller;
|
|
92
75
|
});
|
|
93
76
|
}
|
|
94
77
|
|
|
95
|
-
|
|
78
|
+
createWriteable() {
|
|
96
79
|
return new WritableStream<T>({
|
|
97
80
|
start: () => {
|
|
98
|
-
this
|
|
81
|
+
this.#activeCount += 1;
|
|
99
82
|
},
|
|
100
83
|
write: async (chunk) => {
|
|
101
|
-
await this.
|
|
84
|
+
await this.#readableController.enqueue(chunk);
|
|
102
85
|
},
|
|
103
86
|
abort: () => {
|
|
104
|
-
this
|
|
105
|
-
if (this
|
|
106
|
-
this.
|
|
87
|
+
this.#activeCount -= 1;
|
|
88
|
+
if (this.#activeCount === 0) {
|
|
89
|
+
this.#readableController.close();
|
|
107
90
|
}
|
|
108
91
|
},
|
|
109
92
|
close: () => {
|
|
110
|
-
this
|
|
111
|
-
if (this
|
|
112
|
-
this.
|
|
93
|
+
this.#activeCount -= 1;
|
|
94
|
+
if (this.#activeCount === 0) {
|
|
95
|
+
this.#readableController.close();
|
|
113
96
|
}
|
|
114
97
|
},
|
|
115
98
|
});
|
|
@@ -125,84 +108,99 @@ class MultiplexStream<T> {
|
|
|
125
108
|
* * `resize`: Yes
|
|
126
109
|
*/
|
|
127
110
|
export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
128
|
-
|
|
111
|
+
static isSupported(adb: Adb) {
|
|
129
112
|
return adb.supportsFeature(AdbFeature.ShellV2);
|
|
130
113
|
}
|
|
131
114
|
|
|
132
|
-
|
|
115
|
+
static async pty(adb: Adb, command: string) {
|
|
133
116
|
// TODO: AdbShellSubprocessProtocol: Support setting `XTERM` environment variable
|
|
134
117
|
return new AdbSubprocessShellProtocol(
|
|
135
|
-
await adb.createSocket(`shell,v2,pty:${command}`)
|
|
118
|
+
await adb.createSocket(`shell,v2,pty:${command}`),
|
|
136
119
|
);
|
|
137
120
|
}
|
|
138
121
|
|
|
139
|
-
|
|
122
|
+
static async raw(adb: Adb, command: string) {
|
|
140
123
|
return new AdbSubprocessShellProtocol(
|
|
141
|
-
await adb.createSocket(`shell,v2,raw:${command}`)
|
|
124
|
+
await adb.createSocket(`shell,v2,raw:${command}`),
|
|
142
125
|
);
|
|
143
126
|
}
|
|
144
127
|
|
|
145
|
-
|
|
146
|
-
|
|
128
|
+
readonly #socket: AdbSocket;
|
|
129
|
+
#socketWriter: WritableStreamDefaultWriter<
|
|
147
130
|
Consumable<AdbShellProtocolPacketInit>
|
|
148
131
|
>;
|
|
149
132
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return this
|
|
133
|
+
#stdin: WritableStream<Consumable<Uint8Array>>;
|
|
134
|
+
get stdin() {
|
|
135
|
+
return this.#stdin;
|
|
153
136
|
}
|
|
154
137
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return this
|
|
138
|
+
#stdout: ReadableStream<Uint8Array>;
|
|
139
|
+
get stdout() {
|
|
140
|
+
return this.#stdout;
|
|
158
141
|
}
|
|
159
142
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return this
|
|
143
|
+
#stderr: ReadableStream<Uint8Array>;
|
|
144
|
+
get stderr() {
|
|
145
|
+
return this.#stderr;
|
|
163
146
|
}
|
|
164
147
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return this.
|
|
148
|
+
readonly #exit = new PromiseResolver<number>();
|
|
149
|
+
get exit() {
|
|
150
|
+
return this.#exit.promise;
|
|
168
151
|
}
|
|
169
152
|
|
|
170
|
-
|
|
171
|
-
this
|
|
153
|
+
constructor(socket: AdbSocket) {
|
|
154
|
+
this.#socket = socket;
|
|
172
155
|
|
|
173
156
|
// Check this image to help you understand the stream graph
|
|
174
157
|
// cspell: disable-next-line
|
|
175
158
|
// https://www.plantuml.com/plantuml/png/bL91QiCm4Bpx5SAdv90lb1JISmiw5XzaQKf5PIkiLZIqzEyLSg8ks13gYtOykpFhiOw93N6UGjVDqK7rZsxKqNw0U_NTgVAy4empOy2mm4_olC0VEVEE47GUpnGjKdgXoD76q4GIEpyFhOwP_m28hW0NNzxNUig1_JdW0bA7muFIJDco1daJ_1SAX9bgvoPJPyIkSekhNYctvIGXrCH6tIsPL5fs-s6J5yc9BpWXhKtNdF2LgVYPGM_6GlMwfhWUsIt4lbScANrwlgVVUifPSVi__t44qStnwPvZwobdSmHHlL57p2vFuHS0
|
|
176
159
|
|
|
177
|
-
|
|
160
|
+
let stdoutController!: PushReadableStreamController<Uint8Array>;
|
|
161
|
+
let stderrController!: PushReadableStreamController<Uint8Array>;
|
|
162
|
+
this.#stdout = new PushReadableStream<Uint8Array>((controller) => {
|
|
163
|
+
stdoutController = controller;
|
|
164
|
+
});
|
|
165
|
+
this.#stderr = new PushReadableStream<Uint8Array>((controller) => {
|
|
166
|
+
stderrController = controller;
|
|
167
|
+
});
|
|
178
168
|
|
|
179
|
-
|
|
169
|
+
socket.readable
|
|
180
170
|
.pipeThrough(new StructDeserializeStream(AdbShellProtocolPacket))
|
|
181
|
-
.
|
|
182
|
-
new
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
171
|
+
.pipeTo(
|
|
172
|
+
new WritableStream<AdbShellProtocolPacket>({
|
|
173
|
+
write: async (chunk) => {
|
|
174
|
+
switch (chunk.id) {
|
|
175
|
+
case AdbShellProtocolId.Exit:
|
|
176
|
+
this.#exit.resolve(chunk.data[0]!);
|
|
177
|
+
break;
|
|
178
|
+
case AdbShellProtocolId.Stdout:
|
|
179
|
+
await stdoutController.enqueue(chunk.data);
|
|
180
|
+
break;
|
|
181
|
+
case AdbShellProtocolId.Stderr:
|
|
182
|
+
await stderrController.enqueue(chunk.data);
|
|
183
|
+
break;
|
|
194
184
|
}
|
|
195
|
-
controller.enqueue(chunk);
|
|
196
185
|
},
|
|
197
|
-
})
|
|
186
|
+
}),
|
|
198
187
|
)
|
|
199
|
-
.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
188
|
+
.then(
|
|
189
|
+
() => {
|
|
190
|
+
stdoutController.close();
|
|
191
|
+
stderrController.close();
|
|
192
|
+
// If `#exit` has already resolved, this will be a no-op
|
|
193
|
+
this.#exit.reject(
|
|
194
|
+
new Error("Socket ended without exit message"),
|
|
195
|
+
);
|
|
196
|
+
},
|
|
197
|
+
(e) => {
|
|
198
|
+
stdoutController.error(e);
|
|
199
|
+
stderrController.error(e);
|
|
200
|
+
// If `#exit` has already resolved, this will be a no-op
|
|
201
|
+
this.#exit.reject(e);
|
|
202
|
+
},
|
|
203
|
+
);
|
|
206
204
|
|
|
207
205
|
const multiplexer = new MultiplexStream<
|
|
208
206
|
Consumable<AdbShellProtocolPacketInit>
|
|
@@ -212,34 +210,34 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
212
210
|
new ConsumableTransformStream({
|
|
213
211
|
async transform(chunk, controller) {
|
|
214
212
|
await controller.enqueue(
|
|
215
|
-
AdbShellProtocolPacket.serialize(chunk)
|
|
213
|
+
AdbShellProtocolPacket.serialize(chunk),
|
|
216
214
|
);
|
|
217
215
|
},
|
|
218
|
-
})
|
|
216
|
+
}),
|
|
219
217
|
)
|
|
220
218
|
.pipeTo(socket.writable);
|
|
221
219
|
|
|
222
|
-
this
|
|
220
|
+
this.#stdin = pipeFrom(
|
|
223
221
|
multiplexer.createWriteable(),
|
|
224
|
-
new StdinSerializeStream()
|
|
222
|
+
new StdinSerializeStream(),
|
|
225
223
|
);
|
|
226
224
|
|
|
227
|
-
this
|
|
225
|
+
this.#socketWriter = multiplexer.createWriteable().getWriter();
|
|
228
226
|
}
|
|
229
227
|
|
|
230
|
-
|
|
231
|
-
await ConsumableWritableStream.write(this
|
|
228
|
+
async resize(rows: number, cols: number) {
|
|
229
|
+
await ConsumableWritableStream.write(this.#socketWriter, {
|
|
232
230
|
id: AdbShellProtocolId.WindowSizeChange,
|
|
233
231
|
data: encodeUtf8(
|
|
234
232
|
// The "correct" format is `${rows}x${cols},${x_pixels}x${y_pixels}`
|
|
235
233
|
// However, according to https://linux.die.net/man/4/tty_ioctl
|
|
236
234
|
// `x_pixels` and `y_pixels` are unused, so always sending `0` should be fine.
|
|
237
|
-
`${rows}x${cols},0x0\0
|
|
235
|
+
`${rows}x${cols},0x0\0`,
|
|
238
236
|
),
|
|
239
237
|
});
|
|
240
238
|
}
|
|
241
239
|
|
|
242
|
-
|
|
243
|
-
return this.
|
|
240
|
+
kill() {
|
|
241
|
+
return this.#socket.close();
|
|
244
242
|
}
|
|
245
243
|
}
|
|
@@ -5,8 +5,7 @@ import type {
|
|
|
5
5
|
} from "@yume-chan/stream-extra";
|
|
6
6
|
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
7
7
|
|
|
8
|
-
import type { Adb } from "../../../adb.js";
|
|
9
|
-
import type { AdbSocket } from "../../../socket/index.js";
|
|
8
|
+
import type { Adb, AdbSocket } from "../../../adb.js";
|
|
10
9
|
|
|
11
10
|
export interface AdbSubprocessProtocol {
|
|
12
11
|
/**
|
|
@@ -11,7 +11,7 @@ export interface AdbSyncEntry extends AdbSyncStat {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export const AdbSyncEntryResponse = new Struct({ littleEndian: true })
|
|
14
|
-
.
|
|
14
|
+
.concat(AdbSyncLstatResponse)
|
|
15
15
|
.uint32("nameLength")
|
|
16
16
|
.string("name", { lengthField: "nameLength" })
|
|
17
17
|
.extra({ id: AdbSyncResponseId.Entry as const });
|
|
@@ -20,7 +20,7 @@ export type AdbSyncEntryResponse =
|
|
|
20
20
|
(typeof AdbSyncEntryResponse)["TDeserializeResult"];
|
|
21
21
|
|
|
22
22
|
export const AdbSyncEntry2Response = new Struct({ littleEndian: true })
|
|
23
|
-
.
|
|
23
|
+
.concat(AdbSyncStatResponse)
|
|
24
24
|
.uint32("nameLength")
|
|
25
25
|
.string("name", { lengthField: "nameLength" })
|
|
26
26
|
.extra({ id: AdbSyncResponseId.Entry2 as const });
|
|
@@ -30,7 +30,7 @@ export type AdbSyncEntry2Response =
|
|
|
30
30
|
|
|
31
31
|
export async function* adbSyncOpenDirV2(
|
|
32
32
|
socket: AdbSyncSocket,
|
|
33
|
-
path: string
|
|
33
|
+
path: string,
|
|
34
34
|
): AsyncGenerator<AdbSyncEntry2Response, void, void> {
|
|
35
35
|
const locked = await socket.lock();
|
|
36
36
|
try {
|
|
@@ -38,7 +38,7 @@ export async function* adbSyncOpenDirV2(
|
|
|
38
38
|
for await (const item of adbSyncReadResponses(
|
|
39
39
|
locked,
|
|
40
40
|
AdbSyncResponseId.Entry2,
|
|
41
|
-
AdbSyncEntry2Response
|
|
41
|
+
AdbSyncEntry2Response,
|
|
42
42
|
)) {
|
|
43
43
|
// `LST2` can return error codes for failed `lstat` calls.
|
|
44
44
|
// `LIST` just ignores them.
|
|
@@ -55,7 +55,7 @@ export async function* adbSyncOpenDirV2(
|
|
|
55
55
|
|
|
56
56
|
export async function* adbSyncOpenDirV1(
|
|
57
57
|
socket: AdbSyncSocket,
|
|
58
|
-
path: string
|
|
58
|
+
path: string,
|
|
59
59
|
): AsyncGenerator<AdbSyncEntryResponse, void, void> {
|
|
60
60
|
const locked = await socket.lock();
|
|
61
61
|
try {
|
|
@@ -63,7 +63,7 @@ export async function* adbSyncOpenDirV1(
|
|
|
63
63
|
for await (const item of adbSyncReadResponses(
|
|
64
64
|
locked,
|
|
65
65
|
AdbSyncResponseId.Entry,
|
|
66
|
-
AdbSyncEntryResponse
|
|
66
|
+
AdbSyncEntryResponse,
|
|
67
67
|
)) {
|
|
68
68
|
yield item;
|
|
69
69
|
}
|
|
@@ -75,7 +75,7 @@ export async function* adbSyncOpenDirV1(
|
|
|
75
75
|
export async function* adbSyncOpenDir(
|
|
76
76
|
socket: AdbSyncSocket,
|
|
77
77
|
path: string,
|
|
78
|
-
v2: boolean
|
|
78
|
+
v2: boolean,
|
|
79
79
|
): AsyncGenerator<AdbSyncEntry, void, void> {
|
|
80
80
|
if (v2) {
|
|
81
81
|
yield* adbSyncOpenDirV2(socket, path);
|
|
@@ -16,7 +16,7 @@ export type AdbSyncDataResponse =
|
|
|
16
16
|
|
|
17
17
|
export async function* adbSyncPullGenerator(
|
|
18
18
|
socket: AdbSyncSocket,
|
|
19
|
-
path: string
|
|
19
|
+
path: string,
|
|
20
20
|
): AsyncGenerator<Uint8Array, void, void> {
|
|
21
21
|
const locked = await socket.lock();
|
|
22
22
|
let done = false;
|
|
@@ -25,7 +25,7 @@ export async function* adbSyncPullGenerator(
|
|
|
25
25
|
for await (const packet of adbSyncReadResponses(
|
|
26
26
|
locked,
|
|
27
27
|
AdbSyncResponseId.Data,
|
|
28
|
-
AdbSyncDataResponse
|
|
28
|
+
AdbSyncDataResponse,
|
|
29
29
|
)) {
|
|
30
30
|
yield packet.data;
|
|
31
31
|
}
|
|
@@ -36,7 +36,7 @@ export async function* adbSyncPullGenerator(
|
|
|
36
36
|
for await (const packet of adbSyncReadResponses(
|
|
37
37
|
locked,
|
|
38
38
|
AdbSyncResponseId.Data,
|
|
39
|
-
AdbSyncDataResponse
|
|
39
|
+
AdbSyncDataResponse,
|
|
40
40
|
)) {
|
|
41
41
|
void packet;
|
|
42
42
|
}
|
|
@@ -47,7 +47,7 @@ export async function* adbSyncPullGenerator(
|
|
|
47
47
|
|
|
48
48
|
export function adbSyncPull(
|
|
49
49
|
socket: AdbSyncSocket,
|
|
50
|
-
path: string
|
|
50
|
+
path: string,
|
|
51
51
|
): ReadableStream<Uint8Array> {
|
|
52
52
|
return new PushReadableStream(async (controller) => {
|
|
53
53
|
for await (const data of adbSyncPullGenerator(socket, path)) {
|
|
@@ -6,35 +6,34 @@ import {
|
|
|
6
6
|
} from "@yume-chan/stream-extra";
|
|
7
7
|
import Struct, { placeholder } from "@yume-chan/struct";
|
|
8
8
|
|
|
9
|
+
import { NOOP } from "../../utils/index.js";
|
|
10
|
+
|
|
9
11
|
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|
10
12
|
import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
|
|
11
13
|
import type { AdbSyncSocket, AdbSyncSocketLocked } from "./socket.js";
|
|
12
14
|
import { LinuxFileType } from "./stat.js";
|
|
13
15
|
|
|
14
|
-
const NOOP = () => {
|
|
15
|
-
// no-op
|
|
16
|
-
};
|
|
17
|
-
|
|
18
16
|
export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024;
|
|
19
17
|
|
|
20
18
|
export interface AdbSyncPushV1Options {
|
|
21
19
|
socket: AdbSyncSocket;
|
|
22
20
|
filename: string;
|
|
23
21
|
file: ReadableStream<Consumable<Uint8Array>>;
|
|
24
|
-
|
|
22
|
+
type?: LinuxFileType;
|
|
23
|
+
permission?: number;
|
|
25
24
|
mtime?: number;
|
|
26
25
|
packetSize?: number;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32(
|
|
30
|
-
"unused"
|
|
29
|
+
"unused",
|
|
31
30
|
);
|
|
32
31
|
|
|
33
|
-
async function
|
|
32
|
+
async function pipeFileData(
|
|
34
33
|
locked: AdbSyncSocketLocked,
|
|
35
34
|
file: ReadableStream<Consumable<Uint8Array>>,
|
|
36
35
|
packetSize: number,
|
|
37
|
-
mtime: number
|
|
36
|
+
mtime: number,
|
|
38
37
|
) {
|
|
39
38
|
// Read and write in parallel,
|
|
40
39
|
// allow error response to abort the write.
|
|
@@ -46,11 +45,11 @@ async function pipeFile(
|
|
|
46
45
|
await adbSyncWriteRequest(
|
|
47
46
|
locked,
|
|
48
47
|
AdbSyncRequestId.Data,
|
|
49
|
-
chunk
|
|
48
|
+
chunk,
|
|
50
49
|
);
|
|
51
50
|
},
|
|
52
51
|
}),
|
|
53
|
-
{ signal: abortController.signal }
|
|
52
|
+
{ signal: abortController.signal },
|
|
54
53
|
)
|
|
55
54
|
.then(async () => {
|
|
56
55
|
await adbSyncWriteRequest(locked, AdbSyncRequestId.Done, mtime);
|
|
@@ -60,7 +59,7 @@ async function pipeFile(
|
|
|
60
59
|
await adbSyncReadResponse(
|
|
61
60
|
locked,
|
|
62
61
|
AdbSyncResponseId.Ok,
|
|
63
|
-
AdbSyncOkResponse
|
|
62
|
+
AdbSyncOkResponse,
|
|
64
63
|
).catch((e) => {
|
|
65
64
|
abortController.abort();
|
|
66
65
|
throw e;
|
|
@@ -71,15 +70,17 @@ export async function adbSyncPushV1({
|
|
|
71
70
|
socket,
|
|
72
71
|
filename,
|
|
73
72
|
file,
|
|
74
|
-
|
|
73
|
+
type = LinuxFileType.File,
|
|
74
|
+
permission = 0o666,
|
|
75
75
|
mtime = (Date.now() / 1000) | 0,
|
|
76
76
|
packetSize = ADB_SYNC_MAX_PACKET_SIZE,
|
|
77
77
|
}: AdbSyncPushV1Options) {
|
|
78
78
|
const locked = await socket.lock();
|
|
79
79
|
try {
|
|
80
|
+
const mode = (type << 12) | permission;
|
|
80
81
|
const pathAndMode = `${filename},${mode.toString()}`;
|
|
81
82
|
await adbSyncWriteRequest(locked, AdbSyncRequestId.Send, pathAndMode);
|
|
82
|
-
await
|
|
83
|
+
await pipeFileData(locked, file, packetSize, mtime);
|
|
83
84
|
} finally {
|
|
84
85
|
locked.release();
|
|
85
86
|
}
|
|
@@ -103,6 +104,12 @@ export enum AdbSyncSendV2Flags {
|
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
|
107
|
+
/**
|
|
108
|
+
* Don't write the file to disk. Requires the `sendrecv_v2` feature.
|
|
109
|
+
*
|
|
110
|
+
* It was used during ADB development to benchmark the performance of
|
|
111
|
+
* compression algorithms.
|
|
112
|
+
*/
|
|
106
113
|
dryRun?: boolean;
|
|
107
114
|
}
|
|
108
115
|
|
|
@@ -115,7 +122,8 @@ export async function adbSyncPushV2({
|
|
|
115
122
|
socket,
|
|
116
123
|
filename,
|
|
117
124
|
file,
|
|
118
|
-
|
|
125
|
+
type = LinuxFileType.File,
|
|
126
|
+
permission = 0o666,
|
|
119
127
|
mtime = (Date.now() / 1000) | 0,
|
|
120
128
|
packetSize = ADB_SYNC_MAX_PACKET_SIZE,
|
|
121
129
|
dryRun = false,
|
|
@@ -124,6 +132,7 @@ export async function adbSyncPushV2({
|
|
|
124
132
|
try {
|
|
125
133
|
await adbSyncWriteRequest(locked, AdbSyncRequestId.SendV2, filename);
|
|
126
134
|
|
|
135
|
+
const mode = (type << 12) | permission;
|
|
127
136
|
let flags: AdbSyncSendV2Flags = AdbSyncSendV2Flags.None;
|
|
128
137
|
if (dryRun) {
|
|
129
138
|
flags |= AdbSyncSendV2Flags.DryRun;
|
|
@@ -133,16 +142,19 @@ export async function adbSyncPushV2({
|
|
|
133
142
|
id: AdbSyncRequestId.SendV2,
|
|
134
143
|
mode,
|
|
135
144
|
flags,
|
|
136
|
-
})
|
|
145
|
+
}),
|
|
137
146
|
);
|
|
138
147
|
|
|
139
|
-
await
|
|
148
|
+
await pipeFileData(locked, file, packetSize, mtime);
|
|
140
149
|
} finally {
|
|
141
150
|
locked.release();
|
|
142
151
|
}
|
|
143
152
|
}
|
|
144
153
|
|
|
145
154
|
export interface AdbSyncPushOptions extends AdbSyncPushV2Options {
|
|
155
|
+
/**
|
|
156
|
+
* Whether to use the v2 protocol. Requires the `sendrecv_v2` feature.
|
|
157
|
+
*/
|
|
146
158
|
v2: boolean;
|
|
147
159
|
}
|
|
148
160
|
|
|
@@ -20,7 +20,7 @@ export const AdbSyncNumberRequest = new Struct({ littleEndian: true })
|
|
|
20
20
|
.uint32("arg");
|
|
21
21
|
|
|
22
22
|
export const AdbSyncDataRequest = new Struct({ littleEndian: true })
|
|
23
|
-
.
|
|
23
|
+
.concat(AdbSyncNumberRequest)
|
|
24
24
|
.uint8Array("data", { lengthField: "arg" });
|
|
25
25
|
|
|
26
26
|
export interface AdbSyncWritable {
|
|
@@ -30,7 +30,7 @@ export interface AdbSyncWritable {
|
|
|
30
30
|
export async function adbSyncWriteRequest(
|
|
31
31
|
writable: AdbSyncWritable,
|
|
32
32
|
id: AdbSyncRequestId | string,
|
|
33
|
-
value: number | string | Uint8Array
|
|
33
|
+
value: number | string | Uint8Array,
|
|
34
34
|
): Promise<void> {
|
|
35
35
|
if (typeof value === "number") {
|
|
36
36
|
const buffer = AdbSyncNumberRequest.serialize({
|
|
@@ -42,12 +42,12 @@ export async function adbSyncWriteRequest(
|
|
|
42
42
|
// Let `writable` buffer writes
|
|
43
43
|
const buffer = encodeUtf8(value);
|
|
44
44
|
await writable.write(
|
|
45
|
-
AdbSyncNumberRequest.serialize({ id, arg: buffer.byteLength })
|
|
45
|
+
AdbSyncNumberRequest.serialize({ id, arg: buffer.byteLength }),
|
|
46
46
|
);
|
|
47
47
|
await writable.write(buffer);
|
|
48
48
|
} else {
|
|
49
49
|
await writable.write(
|
|
50
|
-
AdbSyncNumberRequest.serialize({ id, arg: value.byteLength })
|
|
50
|
+
AdbSyncNumberRequest.serialize({ id, arg: value.byteLength }),
|
|
51
51
|
);
|
|
52
52
|
await writable.write(value);
|
|
53
53
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
2
|
+
AsyncExactReadable,
|
|
3
3
|
StructLike,
|
|
4
4
|
StructValueType,
|
|
5
5
|
} from "@yume-chan/struct";
|
|
@@ -19,19 +19,21 @@ export enum AdbSyncResponseId {
|
|
|
19
19
|
Fail = "FAIL",
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
export class AdbSyncError extends Error {}
|
|
23
|
+
|
|
22
24
|
export const AdbSyncFailResponse = new Struct({ littleEndian: true })
|
|
23
25
|
.uint32("messageLength")
|
|
24
26
|
.string("message", { lengthField: "messageLength" })
|
|
25
27
|
.postDeserialize((object) => {
|
|
26
|
-
throw new
|
|
28
|
+
throw new AdbSyncError(object.message);
|
|
27
29
|
});
|
|
28
30
|
|
|
29
31
|
export async function adbSyncReadResponse<T>(
|
|
30
|
-
stream:
|
|
32
|
+
stream: AsyncExactReadable,
|
|
31
33
|
id: AdbSyncResponseId,
|
|
32
|
-
type: StructLike<T
|
|
34
|
+
type: StructLike<T>,
|
|
33
35
|
): Promise<T> {
|
|
34
|
-
const actualId = decodeUtf8(await stream.
|
|
36
|
+
const actualId = decodeUtf8(await stream.readExactly(4));
|
|
35
37
|
switch (actualId) {
|
|
36
38
|
case AdbSyncResponseId.Fail:
|
|
37
39
|
await AdbSyncFailResponse.deserialize(stream);
|
|
@@ -44,14 +46,14 @@ export async function adbSyncReadResponse<T>(
|
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
export async function* adbSyncReadResponses<
|
|
47
|
-
T extends Struct<object, PropertyKey, object, any
|
|
49
|
+
T extends Struct<object, PropertyKey, object, any>,
|
|
48
50
|
>(
|
|
49
|
-
stream:
|
|
51
|
+
stream: AsyncExactReadable,
|
|
50
52
|
id: AdbSyncResponseId,
|
|
51
|
-
type: T
|
|
53
|
+
type: T,
|
|
52
54
|
): AsyncGenerator<StructValueType<T>, void, void> {
|
|
53
55
|
while (true) {
|
|
54
|
-
const actualId = decodeUtf8(await stream.
|
|
56
|
+
const actualId = decodeUtf8(await stream.readExactly(4));
|
|
55
57
|
switch (actualId) {
|
|
56
58
|
case AdbSyncResponseId.Fail:
|
|
57
59
|
await AdbSyncFailResponse.deserialize(stream);
|
|
@@ -61,14 +63,14 @@ export async function* adbSyncReadResponses<
|
|
|
61
63
|
//
|
|
62
64
|
// For example, `DONE` responses for `LIST` requests are 16 bytes (same as `DENT` responses),
|
|
63
65
|
// but `DONE` responses for `STAT` requests are 12 bytes (same as `STAT` responses).
|
|
64
|
-
await stream.
|
|
66
|
+
await stream.readExactly(type.size);
|
|
65
67
|
return;
|
|
66
68
|
case id:
|
|
67
69
|
yield await type.deserialize(stream);
|
|
68
70
|
break;
|
|
69
71
|
default:
|
|
70
72
|
throw new Error(
|
|
71
|
-
`Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${actualId}'
|
|
73
|
+
`Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${actualId}'`,
|
|
72
74
|
);
|
|
73
75
|
}
|
|
74
76
|
}
|