@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
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { PromiseResolver } from "@yume-chan/async";
|
|
2
2
|
import type {
|
|
3
|
-
Consumable,
|
|
4
3
|
PushReadableStreamController,
|
|
5
4
|
ReadableStream,
|
|
6
5
|
WritableStreamDefaultWriter,
|
|
7
6
|
} from "@yume-chan/stream-extra";
|
|
8
7
|
import {
|
|
9
|
-
|
|
8
|
+
MaybeConsumable,
|
|
10
9
|
PushReadableStream,
|
|
11
10
|
StructDeserializeStream,
|
|
12
11
|
WritableStream,
|
|
@@ -64,9 +63,9 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
readonly #socket: AdbSocket;
|
|
67
|
-
#writer: WritableStreamDefaultWriter<
|
|
66
|
+
#writer: WritableStreamDefaultWriter<MaybeConsumable<Uint8Array>>;
|
|
68
67
|
|
|
69
|
-
#stdin: WritableStream<
|
|
68
|
+
#stdin: WritableStream<MaybeConsumable<Uint8Array>>;
|
|
70
69
|
get stdin() {
|
|
71
70
|
return this.#stdin;
|
|
72
71
|
}
|
|
@@ -140,23 +139,20 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
140
139
|
|
|
141
140
|
this.#writer = this.#socket.writable.getWriter();
|
|
142
141
|
|
|
143
|
-
this.#stdin = new WritableStream<
|
|
142
|
+
this.#stdin = new MaybeConsumable.WritableStream<Uint8Array>({
|
|
144
143
|
write: async (chunk) => {
|
|
145
|
-
await
|
|
146
|
-
this.#writer,
|
|
144
|
+
await this.#writer.write(
|
|
147
145
|
AdbShellProtocolPacket.serialize({
|
|
148
146
|
id: AdbShellProtocolId.Stdin,
|
|
149
|
-
data: chunk
|
|
147
|
+
data: chunk,
|
|
150
148
|
}),
|
|
151
149
|
);
|
|
152
|
-
chunk.consume();
|
|
153
150
|
},
|
|
154
151
|
});
|
|
155
152
|
}
|
|
156
153
|
|
|
157
154
|
async resize(rows: number, cols: number) {
|
|
158
|
-
await
|
|
159
|
-
this.#writer,
|
|
155
|
+
await this.#writer.write(
|
|
160
156
|
AdbShellProtocolPacket.serialize({
|
|
161
157
|
id: AdbShellProtocolId.WindowSizeChange,
|
|
162
158
|
// The "correct" format is `${rows}x${cols},${x_pixels}x${y_pixels}`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
2
|
+
MaybeConsumable,
|
|
3
3
|
ReadableStream,
|
|
4
4
|
WritableStream,
|
|
5
5
|
} from "@yume-chan/stream-extra";
|
|
@@ -11,7 +11,7 @@ export interface AdbSubprocessProtocol {
|
|
|
11
11
|
/**
|
|
12
12
|
* A WritableStream that writes to the `stdin` stream.
|
|
13
13
|
*/
|
|
14
|
-
readonly stdin: WritableStream<
|
|
14
|
+
readonly stdin: WritableStream<MaybeConsumable<Uint8Array>>;
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* The `stdout` stream of the process.
|
|
@@ -17,8 +17,7 @@ export interface AdbSyncEntry extends AdbSyncStat {
|
|
|
17
17
|
export const AdbSyncEntryResponse = new Struct({ littleEndian: true })
|
|
18
18
|
.concat(AdbSyncLstatResponse)
|
|
19
19
|
.uint32("nameLength")
|
|
20
|
-
.string("name", { lengthField: "nameLength" })
|
|
21
|
-
.extra({ id: AdbSyncResponseId.Entry as const });
|
|
20
|
+
.string("name", { lengthField: "nameLength" });
|
|
22
21
|
|
|
23
22
|
export type AdbSyncEntryResponse =
|
|
24
23
|
(typeof AdbSyncEntryResponse)["TDeserializeResult"];
|
|
@@ -26,8 +25,7 @@ export type AdbSyncEntryResponse =
|
|
|
26
25
|
export const AdbSyncEntry2Response = new Struct({ littleEndian: true })
|
|
27
26
|
.concat(AdbSyncStatResponse)
|
|
28
27
|
.uint32("nameLength")
|
|
29
|
-
.string("name", { lengthField: "nameLength" })
|
|
30
|
-
.extra({ id: AdbSyncResponseId.Entry2 as const });
|
|
28
|
+
.string("name", { lengthField: "nameLength" });
|
|
31
29
|
|
|
32
30
|
export type AdbSyncEntry2Response =
|
|
33
31
|
(typeof AdbSyncEntry2Response)["TDeserializeResult"];
|
|
@@ -8,8 +8,7 @@ import type { AdbSyncSocket } from "./socket.js";
|
|
|
8
8
|
|
|
9
9
|
export const AdbSyncDataResponse = new Struct({ littleEndian: true })
|
|
10
10
|
.uint32("dataLength")
|
|
11
|
-
.uint8Array("data", { lengthField: "dataLength" })
|
|
12
|
-
.extra({ id: AdbSyncResponseId.Data as const });
|
|
11
|
+
.uint8Array("data", { lengthField: "dataLength" });
|
|
13
12
|
|
|
14
13
|
export type AdbSyncDataResponse =
|
|
15
14
|
(typeof AdbSyncDataResponse)["TDeserializeResult"];
|
|
@@ -52,6 +51,7 @@ export function adbSyncPull(
|
|
|
52
51
|
socket: AdbSyncSocket,
|
|
53
52
|
path: string,
|
|
54
53
|
): ReadableStream<Uint8Array> {
|
|
54
|
+
// TODO: use `ReadableStream.from` when it's supported
|
|
55
55
|
return new PushReadableStream(async (controller) => {
|
|
56
56
|
for await (const data of adbSyncPullGenerator(socket, path)) {
|
|
57
57
|
await controller.enqueue(data);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ReadableStream } from "@yume-chan/stream-extra";
|
|
2
2
|
import {
|
|
3
3
|
AbortController,
|
|
4
|
-
ConsumableWritableStream,
|
|
5
4
|
DistributionStream,
|
|
5
|
+
MaybeConsumable,
|
|
6
6
|
} from "@yume-chan/stream-extra";
|
|
7
7
|
import Struct, { placeholder } from "@yume-chan/struct";
|
|
8
8
|
|
|
@@ -18,7 +18,7 @@ export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024;
|
|
|
18
18
|
export interface AdbSyncPushV1Options {
|
|
19
19
|
socket: AdbSyncSocket;
|
|
20
20
|
filename: string;
|
|
21
|
-
file: ReadableStream<
|
|
21
|
+
file: ReadableStream<MaybeConsumable<Uint8Array>>;
|
|
22
22
|
type?: LinuxFileType;
|
|
23
23
|
permission?: number;
|
|
24
24
|
mtime?: number;
|
|
@@ -31,7 +31,7 @@ export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32(
|
|
|
31
31
|
|
|
32
32
|
async function pipeFileData(
|
|
33
33
|
locked: AdbSyncSocketLocked,
|
|
34
|
-
file: ReadableStream<
|
|
34
|
+
file: ReadableStream<MaybeConsumable<Uint8Array>>,
|
|
35
35
|
packetSize: number,
|
|
36
36
|
mtime: number,
|
|
37
37
|
) {
|
|
@@ -40,7 +40,7 @@ async function pipeFileData(
|
|
|
40
40
|
const abortController = new AbortController();
|
|
41
41
|
file.pipeThrough(new DistributionStream(packetSize, true))
|
|
42
42
|
.pipeTo(
|
|
43
|
-
new
|
|
43
|
+
new MaybeConsumable.WritableStream({
|
|
44
44
|
write: async (chunk) => {
|
|
45
45
|
await adbSyncWriteRequest(
|
|
46
46
|
locked,
|
|
@@ -97,10 +97,7 @@ export enum AdbSyncSendV2Flags {
|
|
|
97
97
|
* 4
|
|
98
98
|
*/
|
|
99
99
|
Zstd = 1 << 2,
|
|
100
|
-
|
|
101
|
-
* 0x80000000
|
|
102
|
-
*/
|
|
103
|
-
DryRun = (1 << 31) >>> 0,
|
|
100
|
+
DryRun = 0x80000000,
|
|
104
101
|
}
|
|
105
102
|
|
|
106
103
|
export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
|
@@ -114,7 +111,7 @@ export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
|
|
114
111
|
}
|
|
115
112
|
|
|
116
113
|
export const AdbSyncSendV2Request = new Struct({ littleEndian: true })
|
|
117
|
-
.uint32("id"
|
|
114
|
+
.uint32("id")
|
|
118
115
|
.uint32("mode")
|
|
119
116
|
.uint32("flags", placeholder<AdbSyncSendV2Flags>());
|
|
120
117
|
|
|
@@ -2,53 +2,53 @@ import Struct from "@yume-chan/struct";
|
|
|
2
2
|
|
|
3
3
|
import { encodeUtf8 } from "../../utils/index.js";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
import { adbSyncEncodeId } from "./response.js";
|
|
6
|
+
|
|
7
|
+
export namespace AdbSyncRequestId {
|
|
8
|
+
export const List = adbSyncEncodeId("LIST");
|
|
9
|
+
export const ListV2 = adbSyncEncodeId("LIS2");
|
|
10
|
+
export const Send = adbSyncEncodeId("SEND");
|
|
11
|
+
export const SendV2 = adbSyncEncodeId("SND2");
|
|
12
|
+
export const Lstat = adbSyncEncodeId("STAT");
|
|
13
|
+
export const Stat = adbSyncEncodeId("STA2");
|
|
14
|
+
export const LstatV2 = adbSyncEncodeId("LST2");
|
|
15
|
+
export const Data = adbSyncEncodeId("DATA");
|
|
16
|
+
export const Done = adbSyncEncodeId("DONE");
|
|
17
|
+
export const Receive = adbSyncEncodeId("RECV");
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export const AdbSyncNumberRequest = new Struct({ littleEndian: true })
|
|
19
|
-
.
|
|
21
|
+
.uint32("id")
|
|
20
22
|
.uint32("arg");
|
|
21
23
|
|
|
22
|
-
export const AdbSyncDataRequest = new Struct({ littleEndian: true })
|
|
23
|
-
.concat(AdbSyncNumberRequest)
|
|
24
|
-
.uint8Array("data", { lengthField: "arg" });
|
|
25
|
-
|
|
26
24
|
export interface AdbSyncWritable {
|
|
27
25
|
write(buffer: Uint8Array): Promise<void>;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
export async function adbSyncWriteRequest(
|
|
31
29
|
writable: AdbSyncWritable,
|
|
32
|
-
id:
|
|
30
|
+
id: number | string,
|
|
33
31
|
value: number | string | Uint8Array,
|
|
34
32
|
): Promise<void> {
|
|
33
|
+
if (typeof id === "string") {
|
|
34
|
+
id = adbSyncEncodeId(id);
|
|
35
|
+
}
|
|
36
|
+
|
|
35
37
|
if (typeof value === "number") {
|
|
36
|
-
const buffer = AdbSyncNumberRequest.serialize({
|
|
37
|
-
id,
|
|
38
|
-
arg: value,
|
|
39
|
-
});
|
|
40
|
-
await writable.write(buffer);
|
|
41
|
-
} else if (typeof value === "string") {
|
|
42
|
-
// Let `writable` buffer writes
|
|
43
|
-
const buffer = encodeUtf8(value);
|
|
44
38
|
await writable.write(
|
|
45
|
-
AdbSyncNumberRequest.serialize({ id, arg:
|
|
39
|
+
AdbSyncNumberRequest.serialize({ id, arg: value }),
|
|
46
40
|
);
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
);
|
|
52
|
-
await writable.write(value);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (typeof value === "string") {
|
|
45
|
+
value = encodeUtf8(value);
|
|
53
46
|
}
|
|
47
|
+
|
|
48
|
+
// `writable` is buffered, it copies inputs to an internal buffer,
|
|
49
|
+
// so don't concatenate headers and data here, that will be an unnecessary copy.
|
|
50
|
+
await writable.write(
|
|
51
|
+
AdbSyncNumberRequest.serialize({ id, arg: value.length }),
|
|
52
|
+
);
|
|
53
|
+
await writable.write(value);
|
|
54
54
|
}
|
|
@@ -1,22 +1,39 @@
|
|
|
1
|
+
import { getUint32LittleEndian } from "@yume-chan/no-data-view";
|
|
1
2
|
import type {
|
|
2
3
|
AsyncExactReadable,
|
|
3
4
|
StructLike,
|
|
4
5
|
StructValueType,
|
|
5
6
|
} from "@yume-chan/struct";
|
|
6
|
-
import Struct from "@yume-chan/struct";
|
|
7
|
+
import Struct, { decodeUtf8 } from "@yume-chan/struct";
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
function encodeAsciiUnchecked(value: string): Uint8Array {
|
|
10
|
+
const result = new Uint8Array(value.length);
|
|
11
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
12
|
+
result[i] = value.charCodeAt(i);
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Encode ID to numbers for faster comparison
|
|
19
|
+
* @param value A 4-character string
|
|
20
|
+
* @returns A 32-bit integer by encoding the string as little-endian
|
|
21
|
+
*/
|
|
22
|
+
export function adbSyncEncodeId(value: string): number {
|
|
23
|
+
const buffer = encodeAsciiUnchecked(value);
|
|
24
|
+
return getUint32LittleEndian(buffer, 0);
|
|
25
|
+
}
|
|
9
26
|
|
|
10
|
-
export
|
|
11
|
-
Entry = "DENT"
|
|
12
|
-
Entry2 = "DNT2"
|
|
13
|
-
Lstat = "STAT"
|
|
14
|
-
Stat = "STA2"
|
|
15
|
-
Lstat2 = "LST2"
|
|
16
|
-
Done = "DONE"
|
|
17
|
-
Data = "DATA"
|
|
18
|
-
Ok = "OKAY"
|
|
19
|
-
Fail = "FAIL"
|
|
27
|
+
export namespace AdbSyncResponseId {
|
|
28
|
+
export const Entry = adbSyncEncodeId("DENT");
|
|
29
|
+
export const Entry2 = adbSyncEncodeId("DNT2");
|
|
30
|
+
export const Lstat = adbSyncEncodeId("STAT");
|
|
31
|
+
export const Stat = adbSyncEncodeId("STA2");
|
|
32
|
+
export const Lstat2 = adbSyncEncodeId("LST2");
|
|
33
|
+
export const Done = adbSyncEncodeId("DONE");
|
|
34
|
+
export const Data = adbSyncEncodeId("DATA");
|
|
35
|
+
export const Ok = adbSyncEncodeId("OKAY");
|
|
36
|
+
export const Fail = adbSyncEncodeId("FAIL");
|
|
20
37
|
}
|
|
21
38
|
|
|
22
39
|
export class AdbSyncError extends Error {}
|
|
@@ -30,18 +47,24 @@ export const AdbSyncFailResponse = new Struct({ littleEndian: true })
|
|
|
30
47
|
|
|
31
48
|
export async function adbSyncReadResponse<T>(
|
|
32
49
|
stream: AsyncExactReadable,
|
|
33
|
-
id:
|
|
50
|
+
id: number | string,
|
|
34
51
|
type: StructLike<T>,
|
|
35
52
|
): Promise<T> {
|
|
36
|
-
|
|
37
|
-
|
|
53
|
+
if (typeof id === "string") {
|
|
54
|
+
id = adbSyncEncodeId(id);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const buffer = await stream.readExactly(4);
|
|
58
|
+
switch (getUint32LittleEndian(buffer, 0)) {
|
|
38
59
|
case AdbSyncResponseId.Fail:
|
|
39
60
|
await AdbSyncFailResponse.deserialize(stream);
|
|
40
61
|
throw new Error("Unreachable");
|
|
41
62
|
case id:
|
|
42
63
|
return await type.deserialize(stream);
|
|
43
64
|
default:
|
|
44
|
-
throw new Error(
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Expected '${id}', but got '${decodeUtf8(buffer)}'`,
|
|
67
|
+
);
|
|
45
68
|
}
|
|
46
69
|
}
|
|
47
70
|
|
|
@@ -49,12 +72,16 @@ export async function* adbSyncReadResponses<
|
|
|
49
72
|
T extends Struct<object, PropertyKey, object, unknown>,
|
|
50
73
|
>(
|
|
51
74
|
stream: AsyncExactReadable,
|
|
52
|
-
id:
|
|
75
|
+
id: number | string,
|
|
53
76
|
type: T,
|
|
54
77
|
): AsyncGenerator<StructValueType<T>, void, void> {
|
|
78
|
+
if (typeof id === "string") {
|
|
79
|
+
id = adbSyncEncodeId(id);
|
|
80
|
+
}
|
|
81
|
+
|
|
55
82
|
while (true) {
|
|
56
|
-
const
|
|
57
|
-
switch (
|
|
83
|
+
const buffer = await stream.readExactly(4);
|
|
84
|
+
switch (getUint32LittleEndian(buffer, 0)) {
|
|
58
85
|
case AdbSyncResponseId.Fail:
|
|
59
86
|
await AdbSyncFailResponse.deserialize(stream);
|
|
60
87
|
throw new Error("Unreachable");
|
|
@@ -70,7 +97,7 @@ export async function* adbSyncReadResponses<
|
|
|
70
97
|
break;
|
|
71
98
|
default:
|
|
72
99
|
throw new Error(
|
|
73
|
-
`Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${
|
|
100
|
+
`Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${decodeUtf8(buffer)}'`,
|
|
74
101
|
);
|
|
75
102
|
}
|
|
76
103
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
2
|
+
MaybeConsumable,
|
|
3
3
|
WritableStreamDefaultWriter,
|
|
4
4
|
} from "@yume-chan/stream-extra";
|
|
5
5
|
import {
|
|
6
6
|
BufferCombiner,
|
|
7
7
|
BufferedReadableStream,
|
|
8
|
-
|
|
8
|
+
Consumable,
|
|
9
9
|
} from "@yume-chan/stream-extra";
|
|
10
10
|
import type { AsyncExactReadable } from "@yume-chan/struct";
|
|
11
11
|
|
|
@@ -13,7 +13,7 @@ import type { AdbSocket } from "../../adb.js";
|
|
|
13
13
|
import { AutoResetEvent } from "../../utils/index.js";
|
|
14
14
|
|
|
15
15
|
export class AdbSyncSocketLocked implements AsyncExactReadable {
|
|
16
|
-
readonly #writer: WritableStreamDefaultWriter<
|
|
16
|
+
readonly #writer: WritableStreamDefaultWriter<MaybeConsumable<Uint8Array>>;
|
|
17
17
|
readonly #readable: BufferedReadableStream;
|
|
18
18
|
readonly #socketLock: AutoResetEvent;
|
|
19
19
|
readonly #writeLock = new AutoResetEvent();
|
|
@@ -24,7 +24,7 @@ export class AdbSyncSocketLocked implements AsyncExactReadable {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
constructor(
|
|
27
|
-
writer: WritableStreamDefaultWriter<
|
|
27
|
+
writer: WritableStreamDefaultWriter<MaybeConsumable<Uint8Array>>,
|
|
28
28
|
readable: BufferedReadableStream,
|
|
29
29
|
bufferSize: number,
|
|
30
30
|
lock: AutoResetEvent,
|
|
@@ -35,8 +35,9 @@ export class AdbSyncSocketLocked implements AsyncExactReadable {
|
|
|
35
35
|
this.#combiner = new BufferCombiner(bufferSize);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
async #
|
|
39
|
-
|
|
38
|
+
async #write(buffer: Uint8Array) {
|
|
39
|
+
// `#combiner` will reuse the buffer, so we need to use the Consumable pattern
|
|
40
|
+
await Consumable.WritableStream.write(this.#writer, buffer);
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
async flush() {
|
|
@@ -44,7 +45,7 @@ export class AdbSyncSocketLocked implements AsyncExactReadable {
|
|
|
44
45
|
await this.#writeLock.wait();
|
|
45
46
|
const buffer = this.#combiner.flush();
|
|
46
47
|
if (buffer) {
|
|
47
|
-
await this.#
|
|
48
|
+
await this.#write(buffer);
|
|
48
49
|
}
|
|
49
50
|
} finally {
|
|
50
51
|
this.#writeLock.notifyOne();
|
|
@@ -55,7 +56,7 @@ export class AdbSyncSocketLocked implements AsyncExactReadable {
|
|
|
55
56
|
try {
|
|
56
57
|
await this.#writeLock.wait();
|
|
57
58
|
for (const buffer of this.#combiner.push(data)) {
|
|
58
|
-
await this.#
|
|
59
|
+
await this.#write(buffer);
|
|
59
60
|
}
|
|
60
61
|
} finally {
|
|
61
62
|
this.#writeLock.notifyOne();
|
|
@@ -63,11 +64,15 @@ export class AdbSyncSocketLocked implements AsyncExactReadable {
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
async readExactly(length: number) {
|
|
67
|
+
// The request may still be in the internal buffer.
|
|
68
|
+
// Call `flush` to send it before starting reading
|
|
66
69
|
await this.flush();
|
|
67
70
|
return await this.#readable.readExactly(length);
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
release(): void {
|
|
74
|
+
// In theory, the writer shouldn't leave anything in the buffer,
|
|
75
|
+
// but to be safe, call `flush` to throw away any remaining data.
|
|
71
76
|
this.#combiner.flush();
|
|
72
77
|
this.#socketLock.notifyOne();
|
|
73
78
|
}
|
|
@@ -29,7 +29,6 @@ export const AdbSyncLstatResponse = new Struct({ littleEndian: true })
|
|
|
29
29
|
.int32("size")
|
|
30
30
|
.int32("mtime")
|
|
31
31
|
.extra({
|
|
32
|
-
id: AdbSyncResponseId.Lstat as const,
|
|
33
32
|
get type() {
|
|
34
33
|
return (this.mode >> 12) as LinuxFileType;
|
|
35
34
|
},
|
|
@@ -83,7 +82,6 @@ export const AdbSyncStatResponse = new Struct({ littleEndian: true })
|
|
|
83
82
|
.uint64("mtime")
|
|
84
83
|
.uint64("ctime")
|
|
85
84
|
.extra({
|
|
86
|
-
id: AdbSyncResponseId.Stat as const,
|
|
87
85
|
get type() {
|
|
88
86
|
return (this.mode >> 12) as LinuxFileType;
|
|
89
87
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AutoDisposable } from "@yume-chan/event";
|
|
2
|
-
import type {
|
|
2
|
+
import type { MaybeConsumable, ReadableStream } from "@yume-chan/stream-extra";
|
|
3
3
|
|
|
4
4
|
import type { Adb, AdbSocket } from "../../adb.js";
|
|
5
5
|
import { AdbFeature } from "../../features.js";
|
|
@@ -9,6 +9,7 @@ import type { AdbSyncEntry } from "./list.js";
|
|
|
9
9
|
import { adbSyncOpenDir } from "./list.js";
|
|
10
10
|
import { adbSyncPull } from "./pull.js";
|
|
11
11
|
import { adbSyncPush } from "./push.js";
|
|
12
|
+
import type { AdbSyncSocketLocked } from "./socket.js";
|
|
12
13
|
import { AdbSyncSocket } from "./socket.js";
|
|
13
14
|
import type { AdbSyncStat, LinuxFileType } from "./stat.js";
|
|
14
15
|
import { adbSyncLstat, adbSyncStat } from "./stat.js";
|
|
@@ -31,7 +32,7 @@ export function dirname(path: string): string {
|
|
|
31
32
|
|
|
32
33
|
export interface AdbSyncWriteOptions {
|
|
33
34
|
filename: string;
|
|
34
|
-
file: ReadableStream<
|
|
35
|
+
file: ReadableStream<MaybeConsumable<Uint8Array>>;
|
|
35
36
|
type?: LinuxFileType;
|
|
36
37
|
permission?: number;
|
|
37
38
|
mtime?: number;
|
|
@@ -150,7 +151,7 @@ export class AdbSync extends AutoDisposable {
|
|
|
150
151
|
*/
|
|
151
152
|
async write(options: AdbSyncWriteOptions): Promise<void> {
|
|
152
153
|
if (this.needPushMkdirWorkaround) {
|
|
153
|
-
// It may fail if
|
|
154
|
+
// It may fail if `filename` already exists.
|
|
154
155
|
// Ignore the result.
|
|
155
156
|
// TODO: sync: test push mkdir workaround (need an Android 8 device)
|
|
156
157
|
await this._adb.subprocess.spawnAndWait([
|
|
@@ -167,6 +168,10 @@ export class AdbSync extends AutoDisposable {
|
|
|
167
168
|
});
|
|
168
169
|
}
|
|
169
170
|
|
|
171
|
+
lockSocket(): Promise<AdbSyncSocketLocked> {
|
|
172
|
+
return this._socket.lock();
|
|
173
|
+
}
|
|
174
|
+
|
|
170
175
|
override async dispose() {
|
|
171
176
|
super.dispose();
|
|
172
177
|
await this._socket.close();
|
package/src/commands/tcpip.ts
CHANGED
|
@@ -47,7 +47,7 @@ export class AdbTcpIpCommand extends AdbCommandBase {
|
|
|
47
47
|
|
|
48
48
|
async setPort(port: number): Promise<string> {
|
|
49
49
|
if (port <= 0) {
|
|
50
|
-
throw new
|
|
50
|
+
throw new TypeError(`Invalid port ${port}`);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const output = await this.adb.createSocketAndWait(`tcpip:${port}`);
|
package/src/daemon/auth.ts
CHANGED