@yume-chan/adb 0.0.23 → 1.0.0
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.md +51 -2
- package/LICENSE +1 -1
- package/README.md +4 -1
- package/esm/adb.d.ts +15 -9
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +5 -2
- package/esm/adb.js.map +1 -1
- package/esm/banner.d.ts +7 -6
- package/esm/banner.d.ts.map +1 -1
- package/esm/banner.js +6 -7
- package/esm/banner.js.map +1 -1
- package/esm/commands/framebuffer.d.ts +63 -34
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +35 -33
- package/esm/commands/framebuffer.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 +12 -12
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +60 -39
- 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/none.js +3 -5
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +22 -14
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +21 -27
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +8 -8
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/list.d.ts +49 -30
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +9 -11
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +7 -9
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +4 -6
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +25 -22
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +14 -21
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.d.ts +20 -23
- package/esm/commands/sync/request.d.ts.map +1 -1
- package/esm/commands/sync/request.js +26 -35
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +25 -19
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +49 -26
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +3 -3
- 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 +75 -54
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +73 -69
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +18 -17
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +8 -8
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts +0 -1
- package/esm/commands/tcpip.d.ts.map +1 -1
- package/esm/commands/tcpip.js +9 -9
- package/esm/commands/tcpip.js.map +1 -1
- package/esm/daemon/auth.d.ts +8 -7
- package/esm/daemon/auth.d.ts.map +1 -1
- package/esm/daemon/auth.js +8 -9
- package/esm/daemon/auth.js.map +1 -1
- package/esm/daemon/crypto.d.ts +4 -3
- package/esm/daemon/crypto.d.ts.map +1 -1
- package/esm/daemon/crypto.js +57 -49
- package/esm/daemon/crypto.js.map +1 -1
- package/esm/daemon/device.d.ts +2 -2
- package/esm/daemon/device.d.ts.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 +46 -33
- package/esm/daemon/dispatcher.js.map +1 -1
- package/esm/daemon/packet.d.ts +48 -32
- package/esm/daemon/packet.d.ts.map +1 -1
- package/esm/daemon/packet.js +36 -32
- package/esm/daemon/packet.js.map +1 -1
- package/esm/daemon/socket.d.ts +11 -11
- package/esm/daemon/socket.d.ts.map +1 -1
- package/esm/daemon/socket.js +19 -40
- package/esm/daemon/socket.js.map +1 -1
- package/esm/daemon/transport.d.ts +60 -20
- package/esm/daemon/transport.d.ts.map +1 -1
- package/esm/daemon/transport.js +12 -15
- package/esm/daemon/transport.js.map +1 -1
- package/esm/device-observer.d.ts +10 -0
- package/esm/device-observer.d.ts.map +1 -0
- package/esm/device-observer.js +2 -0
- package/esm/device-observer.js.map +1 -0
- package/esm/features.d.ts +12 -11
- package/esm/features.d.ts.map +1 -1
- package/esm/features.js +11 -12
- package/esm/features.js.map +1 -1
- package/esm/index.d.ts +1 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -0
- package/esm/index.js.map +1 -1
- package/esm/server/client.d.ts +140 -50
- package/esm/server/client.d.ts.map +1 -1
- package/esm/server/client.js +396 -180
- package/esm/server/client.js.map +1 -1
- package/esm/server/transport.d.ts +2 -2
- package/esm/server/transport.d.ts.map +1 -1
- package/esm/server/transport.js +4 -6
- package/esm/server/transport.js.map +1 -1
- package/esm/utils/base64.d.ts.map +1 -1
- package/esm/utils/base64.js +52 -38
- 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/no-op.d.ts.map +1 -1
- package/esm/utils/no-op.js +1 -0
- package/esm/utils/no-op.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 +14 -19
- package/src/adb.ts +20 -11
- package/src/banner.ts +8 -6
- package/src/commands/framebuffer.ts +44 -35
- package/src/commands/power.ts +7 -5
- package/src/commands/reverse.ts +78 -47
- package/src/commands/subprocess/command.ts +3 -3
- package/src/commands/subprocess/protocols/none.ts +5 -7
- package/src/commands/subprocess/protocols/shell.ts +33 -35
- package/src/commands/subprocess/protocols/types.ts +8 -8
- package/src/commands/sync/list.ts +20 -15
- package/src/commands/sync/pull.ts +9 -8
- package/src/commands/sync/push.ts +25 -24
- package/src/commands/sync/request.ts +37 -38
- package/src/commands/sync/response.ts +63 -37
- package/src/commands/sync/socket.ts +13 -8
- package/src/commands/sync/stat.ts +93 -73
- package/src/commands/sync/sync.ts +12 -11
- package/src/commands/tcpip.ts +9 -9
- package/src/daemon/auth.ts +12 -10
- package/src/daemon/crypto.ts +66 -55
- package/src/daemon/device.ts +2 -2
- package/src/daemon/dispatcher.ts +106 -44
- package/src/daemon/packet.ts +57 -38
- package/src/daemon/socket.ts +30 -50
- package/src/daemon/transport.ts +98 -50
- package/src/device-observer.ts +10 -0
- package/src/features.ts +13 -11
- package/src/index.ts +1 -0
- package/src/server/client.ts +505 -268
- package/src/server/transport.ts +7 -9
- package/src/utils/base64.ts +59 -40
- package/src/utils/hex.ts +16 -14
- package/src/utils/index.ts +1 -1
- package/src/utils/no-op.ts +1 -0
- package/src/utils/sequence-equal.ts +13 -0
- package/tsconfig.build.json +1 -12
- package/tsconfig.build.tsbuildinfo +1 -1
- package/CHANGELOG.json +0 -265
- 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,10 +1,10 @@
|
|
|
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
|
-
import
|
|
7
|
+
import { struct, u32 } from "@yume-chan/struct";
|
|
8
8
|
|
|
9
9
|
import { NOOP } from "../../utils/index.js";
|
|
10
10
|
|
|
@@ -18,20 +18,21 @@ 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;
|
|
25
25
|
packetSize?: number;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export const AdbSyncOkResponse =
|
|
29
|
-
|
|
28
|
+
export const AdbSyncOkResponse = struct(
|
|
29
|
+
{ unused: u32 },
|
|
30
|
+
{ littleEndian: true },
|
|
30
31
|
);
|
|
31
32
|
|
|
32
33
|
async function pipeFileData(
|
|
33
34
|
locked: AdbSyncSocketLocked,
|
|
34
|
-
file: ReadableStream<
|
|
35
|
+
file: ReadableStream<MaybeConsumable<Uint8Array>>,
|
|
35
36
|
packetSize: number,
|
|
36
37
|
mtime: number,
|
|
37
38
|
) {
|
|
@@ -40,9 +41,9 @@ async function pipeFileData(
|
|
|
40
41
|
const abortController = new AbortController();
|
|
41
42
|
file.pipeThrough(new DistributionStream(packetSize, true))
|
|
42
43
|
.pipeTo(
|
|
43
|
-
new
|
|
44
|
-
write
|
|
45
|
-
|
|
44
|
+
new MaybeConsumable.WritableStream({
|
|
45
|
+
write(chunk) {
|
|
46
|
+
return adbSyncWriteRequest(
|
|
46
47
|
locked,
|
|
47
48
|
AdbSyncRequestId.Data,
|
|
48
49
|
chunk,
|
|
@@ -86,22 +87,22 @@ export async function adbSyncPushV1({
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
export
|
|
90
|
-
None
|
|
91
|
-
Brotli
|
|
90
|
+
export const AdbSyncSendV2Flags = {
|
|
91
|
+
None: 0,
|
|
92
|
+
Brotli: 1,
|
|
92
93
|
/**
|
|
93
94
|
* 2
|
|
94
95
|
*/
|
|
95
|
-
Lz4
|
|
96
|
+
Lz4: 1 << 1,
|
|
96
97
|
/**
|
|
97
98
|
* 4
|
|
98
99
|
*/
|
|
99
|
-
Zstd
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
Zstd: 1 << 2,
|
|
101
|
+
DryRun: 0x80000000,
|
|
102
|
+
} as const;
|
|
103
|
+
|
|
104
|
+
export type AdbSyncSendV2Flags =
|
|
105
|
+
(typeof AdbSyncSendV2Flags)[keyof typeof AdbSyncSendV2Flags];
|
|
105
106
|
|
|
106
107
|
export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
|
107
108
|
/**
|
|
@@ -113,10 +114,10 @@ export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
|
|
113
114
|
dryRun?: boolean;
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
export const AdbSyncSendV2Request =
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
export const AdbSyncSendV2Request = struct(
|
|
118
|
+
{ id: u32, mode: u32, flags: u32<AdbSyncSendV2Flags>() },
|
|
119
|
+
{ littleEndian: true },
|
|
120
|
+
);
|
|
120
121
|
|
|
121
122
|
export async function adbSyncPushV2({
|
|
122
123
|
socket,
|
|
@@ -1,27 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export enum AdbSyncRequestId {
|
|
6
|
-
List = "LIST",
|
|
7
|
-
ListV2 = "LIS2",
|
|
8
|
-
Send = "SEND",
|
|
9
|
-
SendV2 = "SND2",
|
|
10
|
-
Lstat = "STAT",
|
|
11
|
-
Stat = "STA2",
|
|
12
|
-
LstatV2 = "LST2",
|
|
13
|
-
Data = "DATA",
|
|
14
|
-
Done = "DONE",
|
|
15
|
-
Receive = "RECV",
|
|
16
|
-
}
|
|
1
|
+
import { encodeUtf8, struct, u32 } from "@yume-chan/struct";
|
|
2
|
+
|
|
3
|
+
import { adbSyncEncodeId } from "./response.js";
|
|
17
4
|
|
|
18
|
-
export const
|
|
19
|
-
|
|
20
|
-
|
|
5
|
+
export const AdbSyncRequestId = {
|
|
6
|
+
List: adbSyncEncodeId("LIST"),
|
|
7
|
+
ListV2: adbSyncEncodeId("LIS2"),
|
|
8
|
+
Send: adbSyncEncodeId("SEND"),
|
|
9
|
+
SendV2: adbSyncEncodeId("SND2"),
|
|
10
|
+
Lstat: adbSyncEncodeId("STAT"),
|
|
11
|
+
Stat: adbSyncEncodeId("STA2"),
|
|
12
|
+
LstatV2: adbSyncEncodeId("LST2"),
|
|
13
|
+
Data: adbSyncEncodeId("DATA"),
|
|
14
|
+
Done: adbSyncEncodeId("DONE"),
|
|
15
|
+
Receive: adbSyncEncodeId("RECV"),
|
|
16
|
+
} as const;
|
|
21
17
|
|
|
22
|
-
export const
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
export const AdbSyncNumberRequest = struct(
|
|
19
|
+
{ id: u32, arg: u32 },
|
|
20
|
+
{ littleEndian: true },
|
|
21
|
+
);
|
|
25
22
|
|
|
26
23
|
export interface AdbSyncWritable {
|
|
27
24
|
write(buffer: Uint8Array): Promise<void>;
|
|
@@ -29,26 +26,28 @@ export interface AdbSyncWritable {
|
|
|
29
26
|
|
|
30
27
|
export async function adbSyncWriteRequest(
|
|
31
28
|
writable: AdbSyncWritable,
|
|
32
|
-
id:
|
|
29
|
+
id: number | string,
|
|
33
30
|
value: number | string | Uint8Array,
|
|
34
31
|
): Promise<void> {
|
|
32
|
+
if (typeof id === "string") {
|
|
33
|
+
id = adbSyncEncodeId(id);
|
|
34
|
+
}
|
|
35
|
+
|
|
35
36
|
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
37
|
await writable.write(
|
|
45
|
-
AdbSyncNumberRequest.serialize({ id, arg:
|
|
38
|
+
AdbSyncNumberRequest.serialize({ id, arg: value }),
|
|
46
39
|
);
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
);
|
|
52
|
-
await writable.write(value);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (typeof value === "string") {
|
|
44
|
+
value = encodeUtf8(value);
|
|
53
45
|
}
|
|
46
|
+
|
|
47
|
+
// `writable` is buffered, it copies inputs to an internal buffer,
|
|
48
|
+
// so don't concatenate headers and data here, that will be an unnecessary copy.
|
|
49
|
+
await writable.write(
|
|
50
|
+
AdbSyncNumberRequest.serialize({ id, arg: value.length }),
|
|
51
|
+
);
|
|
52
|
+
await writable.write(value);
|
|
54
53
|
}
|
|
@@ -1,60 +1,86 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
StructValueType,
|
|
5
|
-
} from "@yume-chan/struct";
|
|
6
|
-
import Struct from "@yume-chan/struct";
|
|
1
|
+
import { getUint32LittleEndian } from "@yume-chan/no-data-view";
|
|
2
|
+
import type { AsyncExactReadable, StructLike } from "@yume-chan/struct";
|
|
3
|
+
import { decodeUtf8, string, struct, u32 } from "@yume-chan/struct";
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
function encodeAsciiUnchecked(value: string): Uint8Array {
|
|
6
|
+
const result = new Uint8Array(value.length);
|
|
7
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
8
|
+
result[i] = value.charCodeAt(i);
|
|
9
|
+
}
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Encode ID to numbers for faster comparison
|
|
15
|
+
* @param value A 4-character string
|
|
16
|
+
* @returns A 32-bit integer by encoding the string as little-endian
|
|
17
|
+
*
|
|
18
|
+
* #__NO_SIDE_EFFECTS__
|
|
19
|
+
*/
|
|
20
|
+
export function adbSyncEncodeId(value: string): number {
|
|
21
|
+
const buffer = encodeAsciiUnchecked(value);
|
|
22
|
+
return getUint32LittleEndian(buffer, 0);
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
export const AdbSyncResponseId = {
|
|
26
|
+
Entry: adbSyncEncodeId("DENT"),
|
|
27
|
+
Entry2: adbSyncEncodeId("DNT2"),
|
|
28
|
+
Lstat: adbSyncEncodeId("STAT"),
|
|
29
|
+
Stat: adbSyncEncodeId("STA2"),
|
|
30
|
+
Lstat2: adbSyncEncodeId("LST2"),
|
|
31
|
+
Done: adbSyncEncodeId("DONE"),
|
|
32
|
+
Data: adbSyncEncodeId("DATA"),
|
|
33
|
+
Ok: adbSyncEncodeId("OKAY"),
|
|
34
|
+
Fail: adbSyncEncodeId("FAIL"),
|
|
35
|
+
};
|
|
36
|
+
|
|
22
37
|
export class AdbSyncError extends Error {}
|
|
23
38
|
|
|
24
|
-
export const AdbSyncFailResponse =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
39
|
+
export const AdbSyncFailResponse = struct(
|
|
40
|
+
{ message: string(u32) },
|
|
41
|
+
{
|
|
42
|
+
littleEndian: true,
|
|
43
|
+
postDeserialize(value) {
|
|
44
|
+
throw new AdbSyncError(value.message);
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
);
|
|
30
48
|
|
|
31
49
|
export async function adbSyncReadResponse<T>(
|
|
32
50
|
stream: AsyncExactReadable,
|
|
33
|
-
id:
|
|
51
|
+
id: number | string,
|
|
34
52
|
type: StructLike<T>,
|
|
35
53
|
): Promise<T> {
|
|
36
|
-
|
|
37
|
-
|
|
54
|
+
if (typeof id === "string") {
|
|
55
|
+
id = adbSyncEncodeId(id);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const buffer = await stream.readExactly(4);
|
|
59
|
+
switch (getUint32LittleEndian(buffer, 0)) {
|
|
38
60
|
case AdbSyncResponseId.Fail:
|
|
39
61
|
await AdbSyncFailResponse.deserialize(stream);
|
|
40
62
|
throw new Error("Unreachable");
|
|
41
63
|
case id:
|
|
42
64
|
return await type.deserialize(stream);
|
|
43
65
|
default:
|
|
44
|
-
throw new Error(
|
|
66
|
+
throw new Error(
|
|
67
|
+
`Expected '${id}', but got '${decodeUtf8(buffer)}'`,
|
|
68
|
+
);
|
|
45
69
|
}
|
|
46
70
|
}
|
|
47
71
|
|
|
48
|
-
export async function* adbSyncReadResponses<
|
|
49
|
-
T extends Struct<object, PropertyKey, object, unknown>,
|
|
50
|
-
>(
|
|
72
|
+
export async function* adbSyncReadResponses<T>(
|
|
51
73
|
stream: AsyncExactReadable,
|
|
52
|
-
id:
|
|
53
|
-
type: T
|
|
54
|
-
): AsyncGenerator<
|
|
74
|
+
id: number | string,
|
|
75
|
+
type: StructLike<T>,
|
|
76
|
+
): AsyncGenerator<T, void, void> {
|
|
77
|
+
if (typeof id === "string") {
|
|
78
|
+
id = adbSyncEncodeId(id);
|
|
79
|
+
}
|
|
80
|
+
|
|
55
81
|
while (true) {
|
|
56
|
-
const
|
|
57
|
-
switch (
|
|
82
|
+
const buffer = await stream.readExactly(4);
|
|
83
|
+
switch (getUint32LittleEndian(buffer, 0)) {
|
|
58
84
|
case AdbSyncResponseId.Fail:
|
|
59
85
|
await AdbSyncFailResponse.deserialize(stream);
|
|
60
86
|
throw new Error("Unreachable");
|
|
@@ -66,11 +92,11 @@ export async function* adbSyncReadResponses<
|
|
|
66
92
|
await stream.readExactly(type.size);
|
|
67
93
|
return;
|
|
68
94
|
case id:
|
|
69
|
-
yield
|
|
95
|
+
yield await type.deserialize(stream);
|
|
70
96
|
break;
|
|
71
97
|
default:
|
|
72
98
|
throw new Error(
|
|
73
|
-
`Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${
|
|
99
|
+
`Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${decodeUtf8(buffer)}'`,
|
|
74
100
|
);
|
|
75
101
|
}
|
|
76
102
|
}
|
|
@@ -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
|
-
|
|
39
|
-
|
|
38
|
+
#write(buffer: Uint8Array) {
|
|
39
|
+
// `#combiner` will reuse the buffer, so we need to use the Consumable pattern
|
|
40
|
+
return 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
|
}
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { StructValue } from "@yume-chan/struct";
|
|
2
|
+
import { struct, u32, u64 } from "@yume-chan/struct";
|
|
2
3
|
|
|
3
4
|
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|
4
5
|
import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
|
|
5
6
|
import type { AdbSyncSocket } from "./socket.js";
|
|
6
7
|
|
|
7
8
|
// https://github.com/python/cpython/blob/4e581d64b8aff3e2eda99b12f080c877bb78dfca/Lib/stat.py#L36
|
|
8
|
-
export
|
|
9
|
-
Directory
|
|
10
|
-
File
|
|
11
|
-
Link
|
|
12
|
-
}
|
|
9
|
+
export const LinuxFileType = {
|
|
10
|
+
Directory: 0o04,
|
|
11
|
+
File: 0o10,
|
|
12
|
+
Link: 0o12,
|
|
13
|
+
} as const;
|
|
14
|
+
|
|
15
|
+
export type LinuxFileType = (typeof LinuxFileType)[keyof typeof LinuxFileType];
|
|
13
16
|
|
|
14
17
|
export interface AdbSyncStat {
|
|
15
18
|
mode: number;
|
|
@@ -24,81 +27,98 @@ export interface AdbSyncStat {
|
|
|
24
27
|
ctime?: bigint;
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
export const AdbSyncLstatResponse =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
export const AdbSyncLstatResponse = struct(
|
|
31
|
+
{ mode: u32, size: u32, mtime: u32 },
|
|
32
|
+
{
|
|
33
|
+
littleEndian: true,
|
|
34
|
+
extra: {
|
|
35
|
+
get type(): LinuxFileType {
|
|
36
|
+
return (this.mode >> 12) as LinuxFileType;
|
|
37
|
+
},
|
|
38
|
+
get permission(): number {
|
|
39
|
+
return this.mode & 0b00001111_11111111;
|
|
40
|
+
},
|
|
35
41
|
},
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
postDeserialize(value) {
|
|
43
|
+
if (value.mode === 0 && value.size === 0 && value.mtime === 0) {
|
|
44
|
+
throw new Error("lstat error");
|
|
45
|
+
}
|
|
46
|
+
return value;
|
|
38
47
|
},
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (object.mode === 0 && object.size === 0 && object.mtime === 0) {
|
|
42
|
-
throw new Error("lstat error");
|
|
43
|
-
}
|
|
44
|
-
});
|
|
48
|
+
},
|
|
49
|
+
);
|
|
45
50
|
|
|
46
|
-
export type AdbSyncLstatResponse =
|
|
47
|
-
(typeof AdbSyncLstatResponse)["TDeserializeResult"];
|
|
51
|
+
export type AdbSyncLstatResponse = StructValue<typeof AdbSyncLstatResponse>;
|
|
48
52
|
|
|
49
|
-
export
|
|
50
|
-
SUCCESS
|
|
51
|
-
EACCES
|
|
52
|
-
EEXIST
|
|
53
|
-
EFAULT
|
|
54
|
-
EFBIG
|
|
55
|
-
EINTR
|
|
56
|
-
EINVAL
|
|
57
|
-
EIO
|
|
58
|
-
EISDIR
|
|
59
|
-
ELOOP
|
|
60
|
-
EMFILE
|
|
61
|
-
ENAMETOOLONG
|
|
62
|
-
ENFILE
|
|
63
|
-
ENOENT
|
|
64
|
-
ENOMEM
|
|
65
|
-
ENOSPC
|
|
66
|
-
ENOTDIR
|
|
67
|
-
EOVERFLOW
|
|
68
|
-
EPERM
|
|
69
|
-
EROFS
|
|
70
|
-
ETXTBSY
|
|
71
|
-
}
|
|
53
|
+
export const AdbSyncStatErrorCode = {
|
|
54
|
+
SUCCESS: 0,
|
|
55
|
+
EACCES: 13,
|
|
56
|
+
EEXIST: 17,
|
|
57
|
+
EFAULT: 14,
|
|
58
|
+
EFBIG: 27,
|
|
59
|
+
EINTR: 4,
|
|
60
|
+
EINVAL: 22,
|
|
61
|
+
EIO: 5,
|
|
62
|
+
EISDIR: 21,
|
|
63
|
+
ELOOP: 40,
|
|
64
|
+
EMFILE: 24,
|
|
65
|
+
ENAMETOOLONG: 36,
|
|
66
|
+
ENFILE: 23,
|
|
67
|
+
ENOENT: 2,
|
|
68
|
+
ENOMEM: 12,
|
|
69
|
+
ENOSPC: 28,
|
|
70
|
+
ENOTDIR: 20,
|
|
71
|
+
EOVERFLOW: 75,
|
|
72
|
+
EPERM: 1,
|
|
73
|
+
EROFS: 30,
|
|
74
|
+
ETXTBSY: 26,
|
|
75
|
+
} as const;
|
|
72
76
|
|
|
73
|
-
export
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
77
|
+
export type AdbSyncStatErrorCode =
|
|
78
|
+
(typeof AdbSyncStatErrorCode)[keyof typeof AdbSyncStatErrorCode];
|
|
79
|
+
|
|
80
|
+
const AdbSyncStatErrorName = /* #__PURE__ */ (() =>
|
|
81
|
+
Object.fromEntries(
|
|
82
|
+
Object.entries(AdbSyncStatErrorCode).map(([key, value]) => [
|
|
83
|
+
value,
|
|
84
|
+
key,
|
|
85
|
+
]),
|
|
86
|
+
))();
|
|
87
|
+
|
|
88
|
+
export const AdbSyncStatResponse = struct(
|
|
89
|
+
{
|
|
90
|
+
error: u32<AdbSyncStatErrorCode>(),
|
|
91
|
+
dev: u64,
|
|
92
|
+
ino: u64,
|
|
93
|
+
mode: u32,
|
|
94
|
+
nlink: u32,
|
|
95
|
+
uid: u32,
|
|
96
|
+
gid: u32,
|
|
97
|
+
size: u64,
|
|
98
|
+
atime: u64,
|
|
99
|
+
mtime: u64,
|
|
100
|
+
ctime: u64,
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
littleEndian: true,
|
|
104
|
+
extra: {
|
|
105
|
+
get type(): LinuxFileType {
|
|
106
|
+
return (this.mode >> 12) as LinuxFileType;
|
|
107
|
+
},
|
|
108
|
+
get permission(): number {
|
|
109
|
+
return this.mode & 0b00001111_11111111;
|
|
110
|
+
},
|
|
89
111
|
},
|
|
90
|
-
|
|
91
|
-
|
|
112
|
+
postDeserialize(value) {
|
|
113
|
+
if (value.error) {
|
|
114
|
+
throw new Error(AdbSyncStatErrorName[value.error]);
|
|
115
|
+
}
|
|
116
|
+
return value;
|
|
92
117
|
},
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (object.error) {
|
|
96
|
-
throw new Error(AdbSyncStatErrorCode[object.error]);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
118
|
+
},
|
|
119
|
+
);
|
|
99
120
|
|
|
100
|
-
export type AdbSyncStatResponse =
|
|
101
|
-
(typeof AdbSyncStatResponse)["TDeserializeResult"];
|
|
121
|
+
export type AdbSyncStatResponse = StructValue<typeof AdbSyncStatResponse>;
|
|
102
122
|
|
|
103
123
|
export async function adbSyncLstat(
|
|
104
124
|
socket: AdbSyncSocket,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Consumable, ReadableStream } from "@yume-chan/stream-extra";
|
|
1
|
+
import type { MaybeConsumable, ReadableStream } from "@yume-chan/stream-extra";
|
|
3
2
|
|
|
4
3
|
import type { Adb, AdbSocket } from "../../adb.js";
|
|
5
4
|
import { AdbFeature } from "../../features.js";
|
|
@@ -9,6 +8,7 @@ import type { AdbSyncEntry } from "./list.js";
|
|
|
9
8
|
import { adbSyncOpenDir } from "./list.js";
|
|
10
9
|
import { adbSyncPull } from "./pull.js";
|
|
11
10
|
import { adbSyncPush } from "./push.js";
|
|
11
|
+
import type { AdbSyncSocketLocked } from "./socket.js";
|
|
12
12
|
import { AdbSyncSocket } from "./socket.js";
|
|
13
13
|
import type { AdbSyncStat, LinuxFileType } from "./stat.js";
|
|
14
14
|
import { adbSyncLstat, adbSyncStat } from "./stat.js";
|
|
@@ -31,14 +31,14 @@ export function dirname(path: string): string {
|
|
|
31
31
|
|
|
32
32
|
export interface AdbSyncWriteOptions {
|
|
33
33
|
filename: string;
|
|
34
|
-
file: ReadableStream<
|
|
34
|
+
file: ReadableStream<MaybeConsumable<Uint8Array>>;
|
|
35
35
|
type?: LinuxFileType;
|
|
36
36
|
permission?: number;
|
|
37
37
|
mtime?: number;
|
|
38
38
|
dryRun?: boolean;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export class AdbSync
|
|
41
|
+
export class AdbSync {
|
|
42
42
|
protected _adb: Adb;
|
|
43
43
|
protected _socket: AdbSyncSocket;
|
|
44
44
|
|
|
@@ -69,8 +69,6 @@ export class AdbSync extends AutoDisposable {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
constructor(adb: Adb, socket: AdbSocket) {
|
|
72
|
-
super();
|
|
73
|
-
|
|
74
72
|
this._adb = adb;
|
|
75
73
|
this._socket = new AdbSyncSocket(socket, adb.maxPayloadSize);
|
|
76
74
|
|
|
@@ -116,7 +114,7 @@ export class AdbSync extends AutoDisposable {
|
|
|
116
114
|
try {
|
|
117
115
|
await this.lstat(path + "/");
|
|
118
116
|
return true;
|
|
119
|
-
} catch
|
|
117
|
+
} catch {
|
|
120
118
|
return false;
|
|
121
119
|
}
|
|
122
120
|
}
|
|
@@ -150,7 +148,7 @@ export class AdbSync extends AutoDisposable {
|
|
|
150
148
|
*/
|
|
151
149
|
async write(options: AdbSyncWriteOptions): Promise<void> {
|
|
152
150
|
if (this.needPushMkdirWorkaround) {
|
|
153
|
-
// It may fail if
|
|
151
|
+
// It may fail if `filename` already exists.
|
|
154
152
|
// Ignore the result.
|
|
155
153
|
// TODO: sync: test push mkdir workaround (need an Android 8 device)
|
|
156
154
|
await this._adb.subprocess.spawnAndWait([
|
|
@@ -167,8 +165,11 @@ export class AdbSync extends AutoDisposable {
|
|
|
167
165
|
});
|
|
168
166
|
}
|
|
169
167
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
168
|
+
lockSocket(): Promise<AdbSyncSocketLocked> {
|
|
169
|
+
return this._socket.lock();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
dispose() {
|
|
173
|
+
return this._socket.close();
|
|
173
174
|
}
|
|
174
175
|
}
|