@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,52 +1,171 @@
|
|
|
1
|
+
import type { Consumable, ReadableStream } from "@yume-chan/stream-extra";
|
|
1
2
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
type BufferedReadableStream,
|
|
6
|
-
type WritableStreamDefaultWriter,
|
|
3
|
+
AbortController,
|
|
4
|
+
ConsumableWritableStream,
|
|
5
|
+
DistributionStream,
|
|
7
6
|
} from "@yume-chan/stream-extra";
|
|
8
|
-
import Struct from "@yume-chan/struct";
|
|
7
|
+
import Struct, { placeholder } from "@yume-chan/struct";
|
|
8
|
+
|
|
9
|
+
import { NOOP } from "../../utils/index.js";
|
|
9
10
|
|
|
10
11
|
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|
11
12
|
import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
|
|
13
|
+
import type { AdbSyncSocket, AdbSyncSocketLocked } from "./socket.js";
|
|
12
14
|
import { LinuxFileType } from "./stat.js";
|
|
13
15
|
|
|
16
|
+
export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024;
|
|
17
|
+
|
|
18
|
+
export interface AdbSyncPushV1Options {
|
|
19
|
+
socket: AdbSyncSocket;
|
|
20
|
+
filename: string;
|
|
21
|
+
file: ReadableStream<Consumable<Uint8Array>>;
|
|
22
|
+
type?: LinuxFileType;
|
|
23
|
+
permission?: number;
|
|
24
|
+
mtime?: number;
|
|
25
|
+
packetSize?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
14
28
|
export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32(
|
|
15
29
|
"unused"
|
|
16
30
|
);
|
|
17
31
|
|
|
18
|
-
|
|
32
|
+
async function pipeFileData(
|
|
33
|
+
locked: AdbSyncSocketLocked,
|
|
34
|
+
file: ReadableStream<Consumable<Uint8Array>>,
|
|
35
|
+
packetSize: number,
|
|
36
|
+
mtime: number
|
|
37
|
+
) {
|
|
38
|
+
// Read and write in parallel,
|
|
39
|
+
// allow error response to abort the write.
|
|
40
|
+
const abortController = new AbortController();
|
|
41
|
+
file.pipeThrough(new DistributionStream(packetSize, true))
|
|
42
|
+
.pipeTo(
|
|
43
|
+
new ConsumableWritableStream({
|
|
44
|
+
write: async (chunk) => {
|
|
45
|
+
await adbSyncWriteRequest(
|
|
46
|
+
locked,
|
|
47
|
+
AdbSyncRequestId.Data,
|
|
48
|
+
chunk
|
|
49
|
+
);
|
|
50
|
+
},
|
|
51
|
+
}),
|
|
52
|
+
{ signal: abortController.signal }
|
|
53
|
+
)
|
|
54
|
+
.then(async () => {
|
|
55
|
+
await adbSyncWriteRequest(locked, AdbSyncRequestId.Done, mtime);
|
|
56
|
+
await locked.flush();
|
|
57
|
+
}, NOOP);
|
|
58
|
+
|
|
59
|
+
await adbSyncReadResponse(
|
|
60
|
+
locked,
|
|
61
|
+
AdbSyncResponseId.Ok,
|
|
62
|
+
AdbSyncOkResponse
|
|
63
|
+
).catch((e) => {
|
|
64
|
+
abortController.abort();
|
|
65
|
+
throw e;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function adbSyncPushV1({
|
|
70
|
+
socket,
|
|
71
|
+
filename,
|
|
72
|
+
file,
|
|
73
|
+
type = LinuxFileType.File,
|
|
74
|
+
permission = 0o666,
|
|
75
|
+
mtime = (Date.now() / 1000) | 0,
|
|
76
|
+
packetSize = ADB_SYNC_MAX_PACKET_SIZE,
|
|
77
|
+
}: AdbSyncPushV1Options) {
|
|
78
|
+
const locked = await socket.lock();
|
|
79
|
+
try {
|
|
80
|
+
const mode = (type << 12) | permission;
|
|
81
|
+
const pathAndMode = `${filename},${mode.toString()}`;
|
|
82
|
+
await adbSyncWriteRequest(locked, AdbSyncRequestId.Send, pathAndMode);
|
|
83
|
+
await pipeFileData(locked, file, packetSize, mtime);
|
|
84
|
+
} finally {
|
|
85
|
+
locked.release();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export enum AdbSyncSendV2Flags {
|
|
90
|
+
None = 0,
|
|
91
|
+
Brotli = 1,
|
|
92
|
+
/**
|
|
93
|
+
* 2
|
|
94
|
+
*/
|
|
95
|
+
Lz4 = 1 << 1,
|
|
96
|
+
/**
|
|
97
|
+
* 4
|
|
98
|
+
*/
|
|
99
|
+
Zstd = 1 << 2,
|
|
100
|
+
/**
|
|
101
|
+
* 0x80000000
|
|
102
|
+
*/
|
|
103
|
+
DryRun = (1 << 31) >>> 0,
|
|
104
|
+
}
|
|
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
|
+
*/
|
|
113
|
+
dryRun?: boolean;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export const AdbSyncSendV2Request = new Struct({ littleEndian: true })
|
|
117
|
+
.uint32("id", placeholder<AdbSyncRequestId>())
|
|
118
|
+
.uint32("mode")
|
|
119
|
+
.uint32("flags", placeholder<AdbSyncSendV2Flags>());
|
|
120
|
+
|
|
121
|
+
export async function adbSyncPushV2({
|
|
122
|
+
socket,
|
|
123
|
+
filename,
|
|
124
|
+
file,
|
|
125
|
+
type = LinuxFileType.File,
|
|
126
|
+
permission = 0o666,
|
|
127
|
+
mtime = (Date.now() / 1000) | 0,
|
|
128
|
+
packetSize = ADB_SYNC_MAX_PACKET_SIZE,
|
|
129
|
+
dryRun = false,
|
|
130
|
+
}: AdbSyncPushV2Options) {
|
|
131
|
+
const locked = await socket.lock();
|
|
132
|
+
try {
|
|
133
|
+
await adbSyncWriteRequest(locked, AdbSyncRequestId.SendV2, filename);
|
|
134
|
+
|
|
135
|
+
const mode = (type << 12) | permission;
|
|
136
|
+
let flags: AdbSyncSendV2Flags = AdbSyncSendV2Flags.None;
|
|
137
|
+
if (dryRun) {
|
|
138
|
+
flags |= AdbSyncSendV2Flags.DryRun;
|
|
139
|
+
}
|
|
140
|
+
await locked.write(
|
|
141
|
+
AdbSyncSendV2Request.serialize({
|
|
142
|
+
id: AdbSyncRequestId.SendV2,
|
|
143
|
+
mode,
|
|
144
|
+
flags,
|
|
145
|
+
})
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
await pipeFileData(locked, file, packetSize, mtime);
|
|
149
|
+
} finally {
|
|
150
|
+
locked.release();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface AdbSyncPushOptions extends AdbSyncPushV2Options {
|
|
155
|
+
/**
|
|
156
|
+
* Whether to use the v2 protocol. Requires the `sendrecv_v2` feature.
|
|
157
|
+
*/
|
|
158
|
+
v2: boolean;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function adbSyncPush(options: AdbSyncPushOptions) {
|
|
162
|
+
if (options.v2) {
|
|
163
|
+
return adbSyncPushV2(options);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (options.dryRun) {
|
|
167
|
+
throw new Error("dryRun is not supported in v1");
|
|
168
|
+
}
|
|
19
169
|
|
|
20
|
-
|
|
21
|
-
stream: BufferedReadableStream,
|
|
22
|
-
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
23
|
-
filename: string,
|
|
24
|
-
mode: number = (LinuxFileType.File << 12) | 0o666,
|
|
25
|
-
mtime: number = (Date.now() / 1000) | 0,
|
|
26
|
-
packetSize: number = ADB_SYNC_MAX_PACKET_SIZE
|
|
27
|
-
): WritableStream<Uint8Array> {
|
|
28
|
-
return pipeFrom(
|
|
29
|
-
new WritableStream<Uint8Array>({
|
|
30
|
-
async start() {
|
|
31
|
-
const pathAndMode = `${filename},${mode.toString()}`;
|
|
32
|
-
await adbSyncWriteRequest(
|
|
33
|
-
writer,
|
|
34
|
-
AdbSyncRequestId.Send,
|
|
35
|
-
pathAndMode
|
|
36
|
-
);
|
|
37
|
-
},
|
|
38
|
-
async write(chunk) {
|
|
39
|
-
await adbSyncWriteRequest(writer, AdbSyncRequestId.Data, chunk);
|
|
40
|
-
},
|
|
41
|
-
async close() {
|
|
42
|
-
await adbSyncWriteRequest(writer, AdbSyncRequestId.Done, mtime);
|
|
43
|
-
await adbSyncReadResponse(
|
|
44
|
-
stream,
|
|
45
|
-
AdbSyncResponseId.Ok,
|
|
46
|
-
AdbSyncOkResponse
|
|
47
|
-
);
|
|
48
|
-
},
|
|
49
|
-
}),
|
|
50
|
-
new ChunkStream(packetSize)
|
|
51
|
-
);
|
|
170
|
+
return adbSyncPushV1(options);
|
|
52
171
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { type WritableStreamDefaultWriter } from "@yume-chan/stream-extra";
|
|
2
1
|
import Struct from "@yume-chan/struct";
|
|
3
2
|
|
|
4
3
|
import { encodeUtf8 } from "../../utils/index.js";
|
|
5
4
|
|
|
6
5
|
export enum AdbSyncRequestId {
|
|
7
6
|
List = "LIST",
|
|
8
|
-
|
|
7
|
+
ListV2 = "LIS2",
|
|
9
8
|
Send = "SEND",
|
|
9
|
+
SendV2 = "SND2",
|
|
10
10
|
Lstat = "STAT",
|
|
11
11
|
Stat = "STA2",
|
|
12
|
-
|
|
12
|
+
LstatV2 = "LST2",
|
|
13
13
|
Data = "DATA",
|
|
14
14
|
Done = "DONE",
|
|
15
15
|
Receive = "RECV",
|
|
@@ -20,30 +20,35 @@ 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
|
+
export interface AdbSyncWritable {
|
|
27
|
+
write(buffer: Uint8Array): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
|
|
26
30
|
export async function adbSyncWriteRequest(
|
|
27
|
-
|
|
31
|
+
writable: AdbSyncWritable,
|
|
28
32
|
id: AdbSyncRequestId | string,
|
|
29
33
|
value: number | string | Uint8Array
|
|
30
34
|
): Promise<void> {
|
|
31
|
-
let buffer: Uint8Array;
|
|
32
35
|
if (typeof value === "number") {
|
|
33
|
-
buffer = AdbSyncNumberRequest.serialize({
|
|
36
|
+
const buffer = AdbSyncNumberRequest.serialize({
|
|
34
37
|
id,
|
|
35
38
|
arg: value,
|
|
36
39
|
});
|
|
40
|
+
await writable.write(buffer);
|
|
37
41
|
} else if (typeof value === "string") {
|
|
38
|
-
buffer
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
// Let `writable` buffer writes
|
|
43
|
+
const buffer = encodeUtf8(value);
|
|
44
|
+
await writable.write(
|
|
45
|
+
AdbSyncNumberRequest.serialize({ id, arg: buffer.byteLength })
|
|
46
|
+
);
|
|
47
|
+
await writable.write(buffer);
|
|
42
48
|
} else {
|
|
43
|
-
|
|
44
|
-
id,
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
await writable.write(
|
|
50
|
+
AdbSyncNumberRequest.serialize({ id, arg: value.byteLength })
|
|
51
|
+
);
|
|
52
|
+
await writable.write(value);
|
|
47
53
|
}
|
|
48
|
-
await writer.write(buffer);
|
|
49
54
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type {
|
|
2
|
+
AsyncExactReadable,
|
|
3
|
+
StructLike,
|
|
4
|
+
StructValueType,
|
|
5
5
|
} from "@yume-chan/struct";
|
|
6
|
+
import Struct from "@yume-chan/struct";
|
|
6
7
|
|
|
7
8
|
import { decodeUtf8 } from "../../utils/index.js";
|
|
8
9
|
|
|
@@ -26,11 +27,11 @@ export const AdbSyncFailResponse = new Struct({ littleEndian: true })
|
|
|
26
27
|
});
|
|
27
28
|
|
|
28
29
|
export async function adbSyncReadResponse<T>(
|
|
29
|
-
stream:
|
|
30
|
+
stream: AsyncExactReadable,
|
|
30
31
|
id: AdbSyncResponseId,
|
|
31
32
|
type: StructLike<T>
|
|
32
33
|
): Promise<T> {
|
|
33
|
-
const actualId = decodeUtf8(await stream.
|
|
34
|
+
const actualId = decodeUtf8(await stream.readExactly(4));
|
|
34
35
|
switch (actualId) {
|
|
35
36
|
case AdbSyncResponseId.Fail:
|
|
36
37
|
await AdbSyncFailResponse.deserialize(stream);
|
|
@@ -45,12 +46,12 @@ export async function adbSyncReadResponse<T>(
|
|
|
45
46
|
export async function* adbSyncReadResponses<
|
|
46
47
|
T extends Struct<object, PropertyKey, object, any>
|
|
47
48
|
>(
|
|
48
|
-
stream:
|
|
49
|
+
stream: AsyncExactReadable,
|
|
49
50
|
id: AdbSyncResponseId,
|
|
50
51
|
type: T
|
|
51
52
|
): AsyncGenerator<StructValueType<T>, void, void> {
|
|
52
53
|
while (true) {
|
|
53
|
-
const actualId = decodeUtf8(await stream.
|
|
54
|
+
const actualId = decodeUtf8(await stream.readExactly(4));
|
|
54
55
|
switch (actualId) {
|
|
55
56
|
case AdbSyncResponseId.Fail:
|
|
56
57
|
await AdbSyncFailResponse.deserialize(stream);
|
|
@@ -60,7 +61,7 @@ export async function* adbSyncReadResponses<
|
|
|
60
61
|
//
|
|
61
62
|
// For example, `DONE` responses for `LIST` requests are 16 bytes (same as `DENT` responses),
|
|
62
63
|
// but `DONE` responses for `STAT` requests are 12 bytes (same as `STAT` responses).
|
|
63
|
-
await stream.
|
|
64
|
+
await stream.readExactly(type.size);
|
|
64
65
|
return;
|
|
65
66
|
case id:
|
|
66
67
|
yield await type.deserialize(stream);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Consumable,
|
|
3
|
+
WritableStreamDefaultWriter,
|
|
4
|
+
} from "@yume-chan/stream-extra";
|
|
5
|
+
import {
|
|
6
|
+
BufferCombiner,
|
|
7
|
+
BufferedReadableStream,
|
|
8
|
+
ConsumableWritableStream,
|
|
9
|
+
} from "@yume-chan/stream-extra";
|
|
10
|
+
import type { AsyncExactReadable } from "@yume-chan/struct";
|
|
11
|
+
|
|
12
|
+
import type { AdbSocket } from "../../adb.js";
|
|
13
|
+
import { AutoResetEvent } from "../../utils/index.js";
|
|
14
|
+
|
|
15
|
+
export class AdbSyncSocketLocked implements AsyncExactReadable {
|
|
16
|
+
readonly #writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>;
|
|
17
|
+
readonly #readable: BufferedReadableStream;
|
|
18
|
+
readonly #socketLock: AutoResetEvent;
|
|
19
|
+
readonly #writeLock = new AutoResetEvent();
|
|
20
|
+
readonly #combiner: BufferCombiner;
|
|
21
|
+
|
|
22
|
+
public get position() {
|
|
23
|
+
return this.#readable.position;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public constructor(
|
|
27
|
+
writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>,
|
|
28
|
+
readable: BufferedReadableStream,
|
|
29
|
+
bufferSize: number,
|
|
30
|
+
lock: AutoResetEvent
|
|
31
|
+
) {
|
|
32
|
+
this.#writer = writer;
|
|
33
|
+
this.#readable = readable;
|
|
34
|
+
this.#socketLock = lock;
|
|
35
|
+
this.#combiner = new BufferCombiner(bufferSize);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private async writeInnerStream(buffer: Uint8Array) {
|
|
39
|
+
await ConsumableWritableStream.write(this.#writer, buffer);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public async flush() {
|
|
43
|
+
try {
|
|
44
|
+
await this.#writeLock.wait();
|
|
45
|
+
const buffer = this.#combiner.flush();
|
|
46
|
+
if (buffer) {
|
|
47
|
+
await this.writeInnerStream(buffer);
|
|
48
|
+
}
|
|
49
|
+
} finally {
|
|
50
|
+
this.#writeLock.notifyOne();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public async write(data: Uint8Array) {
|
|
55
|
+
try {
|
|
56
|
+
await this.#writeLock.wait();
|
|
57
|
+
for (const buffer of this.#combiner.push(data)) {
|
|
58
|
+
await this.writeInnerStream(buffer);
|
|
59
|
+
}
|
|
60
|
+
} finally {
|
|
61
|
+
this.#writeLock.notifyOne();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public async readExactly(length: number) {
|
|
66
|
+
await this.flush();
|
|
67
|
+
return await this.#readable.readExactly(length);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public release(): void {
|
|
71
|
+
this.#combiner.flush();
|
|
72
|
+
this.#socketLock.notifyOne();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export class AdbSyncSocket {
|
|
77
|
+
readonly #lock = new AutoResetEvent();
|
|
78
|
+
readonly #socket: AdbSocket;
|
|
79
|
+
readonly #locked: AdbSyncSocketLocked;
|
|
80
|
+
|
|
81
|
+
public constructor(socket: AdbSocket, bufferSize: number) {
|
|
82
|
+
this.#socket = socket;
|
|
83
|
+
this.#locked = new AdbSyncSocketLocked(
|
|
84
|
+
socket.writable.getWriter(),
|
|
85
|
+
new BufferedReadableStream(socket.readable),
|
|
86
|
+
bufferSize,
|
|
87
|
+
this.#lock
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public async lock() {
|
|
92
|
+
await this.#lock.wait();
|
|
93
|
+
return this.#locked;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public async close() {
|
|
97
|
+
await this.#socket.close();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type BufferedReadableStream,
|
|
3
|
-
type WritableStreamDefaultWriter,
|
|
4
|
-
} from "@yume-chan/stream-extra";
|
|
5
1
|
import Struct, { placeholder } from "@yume-chan/struct";
|
|
6
2
|
|
|
7
3
|
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|
8
4
|
import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
|
|
5
|
+
import type { AdbSyncSocket } from "./socket.js";
|
|
9
6
|
|
|
10
7
|
// https://github.com/python/cpython/blob/4e581d64b8aff3e2eda99b12f080c877bb78dfca/Lib/stat.py#L36
|
|
11
8
|
export enum LinuxFileType {
|
|
@@ -47,7 +44,7 @@ export const AdbSyncLstatResponse = new Struct({ littleEndian: true })
|
|
|
47
44
|
});
|
|
48
45
|
|
|
49
46
|
export type AdbSyncLstatResponse =
|
|
50
|
-
typeof AdbSyncLstatResponse["TDeserializeResult"];
|
|
47
|
+
(typeof AdbSyncLstatResponse)["TDeserializeResult"];
|
|
51
48
|
|
|
52
49
|
export enum AdbSyncStatErrorCode {
|
|
53
50
|
SUCCESS = 0,
|
|
@@ -101,52 +98,60 @@ export const AdbSyncStatResponse = new Struct({ littleEndian: true })
|
|
|
101
98
|
});
|
|
102
99
|
|
|
103
100
|
export type AdbSyncStatResponse =
|
|
104
|
-
typeof AdbSyncStatResponse["TDeserializeResult"];
|
|
101
|
+
(typeof AdbSyncStatResponse)["TDeserializeResult"];
|
|
105
102
|
|
|
106
103
|
export async function adbSyncLstat(
|
|
107
|
-
|
|
108
|
-
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
104
|
+
socket: AdbSyncSocket,
|
|
109
105
|
path: string,
|
|
110
106
|
v2: boolean
|
|
111
107
|
): Promise<AdbSyncStat> {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
108
|
+
const locked = await socket.lock();
|
|
109
|
+
try {
|
|
110
|
+
if (v2) {
|
|
111
|
+
await adbSyncWriteRequest(locked, AdbSyncRequestId.LstatV2, path);
|
|
112
|
+
return await adbSyncReadResponse(
|
|
113
|
+
locked,
|
|
114
|
+
AdbSyncResponseId.Lstat2,
|
|
115
|
+
AdbSyncStatResponse
|
|
116
|
+
);
|
|
117
|
+
} else {
|
|
118
|
+
await adbSyncWriteRequest(locked, AdbSyncRequestId.Lstat, path);
|
|
119
|
+
const response = await adbSyncReadResponse(
|
|
120
|
+
locked,
|
|
121
|
+
AdbSyncResponseId.Lstat,
|
|
122
|
+
AdbSyncLstatResponse
|
|
123
|
+
);
|
|
124
|
+
return {
|
|
125
|
+
mode: response.mode,
|
|
126
|
+
// Convert to `BigInt` to make it compatible with `AdbSyncStatResponse`
|
|
127
|
+
size: BigInt(response.size),
|
|
128
|
+
mtime: BigInt(response.mtime),
|
|
129
|
+
get type() {
|
|
130
|
+
return response.type;
|
|
131
|
+
},
|
|
132
|
+
get permission() {
|
|
133
|
+
return response.permission;
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
} finally {
|
|
138
|
+
locked.release();
|
|
138
139
|
}
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
export async function adbSyncStat(
|
|
142
|
-
|
|
143
|
-
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
143
|
+
socket: AdbSyncSocket,
|
|
144
144
|
path: string
|
|
145
145
|
): Promise<AdbSyncStatResponse> {
|
|
146
|
-
await
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
146
|
+
const locked = await socket.lock();
|
|
147
|
+
try {
|
|
148
|
+
await adbSyncWriteRequest(locked, AdbSyncRequestId.Stat, path);
|
|
149
|
+
return await adbSyncReadResponse(
|
|
150
|
+
locked,
|
|
151
|
+
AdbSyncResponseId.Stat,
|
|
152
|
+
AdbSyncStatResponse
|
|
153
|
+
);
|
|
154
|
+
} finally {
|
|
155
|
+
locked.release();
|
|
156
|
+
}
|
|
152
157
|
}
|