@yume-chan/adb 0.0.17 → 0.0.19
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 +27 -0
- package/CHANGELOG.md +16 -1
- package/LICENSE +1 -1
- package/esm/adb.d.ts +63 -60
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +257 -229
- package/esm/adb.js.map +1 -1
- package/esm/auth.d.ts +51 -51
- package/esm/auth.d.ts.map +1 -1
- package/esm/auth.js +95 -96
- package/esm/auth.js.map +1 -1
- package/esm/backend.d.ts +8 -8
- package/esm/backend.d.ts.map +1 -1
- package/esm/backend.js +1 -1
- package/esm/commands/base.d.ts +6 -6
- 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 -47
- 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/install.d.ts +9 -3
- package/esm/commands/install.d.ts.map +1 -1
- package/esm/commands/install.js +27 -21
- package/esm/commands/install.js.map +1 -1
- package/esm/commands/power.d.ts +22 -22
- package/esm/commands/power.d.ts.map +1 -1
- package/esm/commands/power.js +48 -44
- package/esm/commands/power.js.map +1 -1
- package/esm/commands/reverse.d.ts +41 -28
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +125 -98
- 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 -82
- 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 +35 -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 +39 -38
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +166 -154
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +49 -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 -35
- 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 -36
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +46 -7
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +89 -23
- 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 +27 -0
- package/esm/commands/sync/socket.d.ts.map +1 -0
- package/esm/commands/sync/socket.js +66 -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 -94
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +72 -60
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +127 -148
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts +5 -5
- package/esm/commands/tcpip.js +18 -18
- package/esm/crypto.d.ts +36 -36
- package/esm/crypto.d.ts.map +1 -1
- package/esm/crypto.js +248 -238
- package/esm/crypto.js.map +1 -1
- 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 +9 -9
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +9 -9
- package/esm/index.js.map +1 -1
- package/esm/packet.d.ts +45 -46
- package/esm/packet.d.ts.map +1 -1
- package/esm/packet.js +43 -46
- package/esm/packet.js.map +1 -1
- package/esm/socket/dispatcher.d.ts +59 -59
- package/esm/socket/dispatcher.d.ts.map +1 -1
- package/esm/socket/dispatcher.js +223 -231
- package/esm/socket/dispatcher.js.map +1 -1
- package/esm/socket/index.d.ts +2 -2
- package/esm/socket/index.js +2 -2
- package/esm/socket/socket.d.ts +59 -59
- package/esm/socket/socket.d.ts.map +1 -1
- package/esm/socket/socket.js +118 -98
- package/esm/socket/socket.js.map +1 -1
- package/esm/utils/auto-reset-event.d.ts +9 -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.d.ts.map +1 -1
- package/esm/utils/base64.js +246 -245
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/conditional-variable.d.ts +9 -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/index.d.ts +4 -3
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +4 -3
- package/esm/utils/index.js.map +1 -1
- package/package.json +17 -13
- package/src/adb.ts +160 -101
- package/src/auth.ts +31 -22
- package/src/backend.ts +6 -4
- package/src/commands/base.ts +2 -2
- package/src/commands/framebuffer.ts +37 -41
- package/src/commands/index.ts +7 -8
- package/src/commands/power.ts +15 -11
- package/src/commands/reverse.ts +74 -30
- package/src/commands/subprocess/command.ts +34 -23
- package/src/commands/subprocess/index.ts +3 -3
- package/src/commands/subprocess/protocols/index.ts +3 -3
- package/src/commands/subprocess/protocols/none.ts +26 -11
- package/src/commands/subprocess/protocols/shell.ts +110 -56
- package/src/commands/subprocess/protocols/types.ts +10 -6
- package/src/commands/subprocess/utils.ts +1 -1
- package/src/commands/sync/index.ts +8 -7
- package/src/commands/sync/list.ts +74 -28
- package/src/commands/sync/pull.ts +49 -37
- package/src/commands/sync/push.ts +153 -32
- package/src/commands/sync/request.ts +37 -34
- package/src/commands/sync/response.ts +34 -27
- package/src/commands/sync/socket.ts +97 -0
- package/src/commands/sync/stat.ts +98 -70
- package/src/commands/sync/sync.ts +78 -97
- package/src/commands/tcpip.ts +5 -5
- package/src/crypto.ts +60 -32
- package/src/features.ts +9 -6
- package/src/index.ts +9 -10
- package/src/packet.ts +41 -46
- package/src/socket/dispatcher.ts +130 -108
- package/src/socket/index.ts +2 -2
- package/src/socket/socket.ts +84 -34
- package/src/utils/auto-reset-event.ts +16 -17
- package/src/utils/base64.ts +51 -41
- package/src/utils/conditional-variable.ts +45 -0
- package/src/utils/index.ts +4 -3
- package/tsconfig.build.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/src/commands/install.ts +0 -32
|
@@ -1,38 +1,159 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import type { Consumable, ReadableStream } from "@yume-chan/stream-extra";
|
|
2
|
+
import {
|
|
3
|
+
AbortController,
|
|
4
|
+
ConsumableWritableStream,
|
|
5
|
+
DistributionStream,
|
|
6
|
+
} from "@yume-chan/stream-extra";
|
|
7
|
+
import Struct, { placeholder } from "@yume-chan/struct";
|
|
3
8
|
|
|
4
|
-
import { AdbSyncRequestId, adbSyncWriteRequest } from
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
9
|
+
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|
10
|
+
import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
|
|
11
|
+
import type { AdbSyncSocket, AdbSyncSocketLocked } from "./socket.js";
|
|
12
|
+
import { LinuxFileType } from "./stat.js";
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
const NOOP = () => {
|
|
15
|
+
// no-op
|
|
16
|
+
};
|
|
11
17
|
|
|
12
18
|
export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024;
|
|
13
19
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
mode
|
|
19
|
-
mtime
|
|
20
|
-
packetSize
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
20
|
+
export interface AdbSyncPushV1Options {
|
|
21
|
+
socket: AdbSyncSocket;
|
|
22
|
+
filename: string;
|
|
23
|
+
file: ReadableStream<Consumable<Uint8Array>>;
|
|
24
|
+
mode?: number;
|
|
25
|
+
mtime?: number;
|
|
26
|
+
packetSize?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32(
|
|
30
|
+
"unused"
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
async function pipeFile(
|
|
34
|
+
locked: AdbSyncSocketLocked,
|
|
35
|
+
file: ReadableStream<Consumable<Uint8Array>>,
|
|
36
|
+
packetSize: number,
|
|
37
|
+
mtime: number
|
|
38
|
+
) {
|
|
39
|
+
// Read and write in parallel,
|
|
40
|
+
// allow error response to abort the write.
|
|
41
|
+
const abortController = new AbortController();
|
|
42
|
+
file.pipeThrough(new DistributionStream(packetSize, true))
|
|
43
|
+
.pipeTo(
|
|
44
|
+
new ConsumableWritableStream({
|
|
45
|
+
write: async (chunk) => {
|
|
46
|
+
await adbSyncWriteRequest(
|
|
47
|
+
locked,
|
|
48
|
+
AdbSyncRequestId.Data,
|
|
49
|
+
chunk
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
}),
|
|
53
|
+
{ signal: abortController.signal }
|
|
54
|
+
)
|
|
55
|
+
.then(async () => {
|
|
56
|
+
await adbSyncWriteRequest(locked, AdbSyncRequestId.Done, mtime);
|
|
57
|
+
await locked.flush();
|
|
58
|
+
}, NOOP);
|
|
59
|
+
|
|
60
|
+
await adbSyncReadResponse(
|
|
61
|
+
locked,
|
|
62
|
+
AdbSyncResponseId.Ok,
|
|
63
|
+
AdbSyncOkResponse
|
|
64
|
+
).catch((e) => {
|
|
65
|
+
abortController.abort();
|
|
66
|
+
throw e;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function adbSyncPushV1({
|
|
71
|
+
socket,
|
|
72
|
+
filename,
|
|
73
|
+
file,
|
|
74
|
+
mode = (LinuxFileType.File << 12) | 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 pathAndMode = `${filename},${mode.toString()}`;
|
|
81
|
+
await adbSyncWriteRequest(locked, AdbSyncRequestId.Send, pathAndMode);
|
|
82
|
+
await pipeFile(locked, file, packetSize, mtime);
|
|
83
|
+
} finally {
|
|
84
|
+
locked.release();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export enum AdbSyncSendV2Flags {
|
|
89
|
+
None = 0,
|
|
90
|
+
Brotli = 1,
|
|
91
|
+
/**
|
|
92
|
+
* 2
|
|
93
|
+
*/
|
|
94
|
+
Lz4 = 1 << 1,
|
|
95
|
+
/**
|
|
96
|
+
* 4
|
|
97
|
+
*/
|
|
98
|
+
Zstd = 1 << 2,
|
|
99
|
+
/**
|
|
100
|
+
* 0x80000000
|
|
101
|
+
*/
|
|
102
|
+
DryRun = (1 << 31) >>> 0,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
|
106
|
+
dryRun?: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const AdbSyncSendV2Request = new Struct({ littleEndian: true })
|
|
110
|
+
.uint32("id", placeholder<AdbSyncRequestId>())
|
|
111
|
+
.uint32("mode")
|
|
112
|
+
.uint32("flags", placeholder<AdbSyncSendV2Flags>());
|
|
113
|
+
|
|
114
|
+
export async function adbSyncPushV2({
|
|
115
|
+
socket,
|
|
116
|
+
filename,
|
|
117
|
+
file,
|
|
118
|
+
mode = (LinuxFileType.File << 12) | 0o666,
|
|
119
|
+
mtime = (Date.now() / 1000) | 0,
|
|
120
|
+
packetSize = ADB_SYNC_MAX_PACKET_SIZE,
|
|
121
|
+
dryRun = false,
|
|
122
|
+
}: AdbSyncPushV2Options) {
|
|
123
|
+
const locked = await socket.lock();
|
|
124
|
+
try {
|
|
125
|
+
await adbSyncWriteRequest(locked, AdbSyncRequestId.SendV2, filename);
|
|
126
|
+
|
|
127
|
+
let flags: AdbSyncSendV2Flags = AdbSyncSendV2Flags.None;
|
|
128
|
+
if (dryRun) {
|
|
129
|
+
flags |= AdbSyncSendV2Flags.DryRun;
|
|
130
|
+
}
|
|
131
|
+
await locked.write(
|
|
132
|
+
AdbSyncSendV2Request.serialize({
|
|
133
|
+
id: AdbSyncRequestId.SendV2,
|
|
134
|
+
mode,
|
|
135
|
+
flags,
|
|
136
|
+
})
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
await pipeFile(locked, file, packetSize, mtime);
|
|
140
|
+
} finally {
|
|
141
|
+
locked.release();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface AdbSyncPushOptions extends AdbSyncPushV2Options {
|
|
146
|
+
v2: boolean;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function adbSyncPush(options: AdbSyncPushOptions) {
|
|
150
|
+
if (options.v2) {
|
|
151
|
+
return adbSyncPushV2(options);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (options.dryRun) {
|
|
155
|
+
throw new Error("dryRun is not supported in v1");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return adbSyncPushV1(options);
|
|
38
159
|
}
|
|
@@ -1,51 +1,54 @@
|
|
|
1
|
-
import
|
|
2
|
-
import Struct from '@yume-chan/struct';
|
|
1
|
+
import Struct from "@yume-chan/struct";
|
|
3
2
|
|
|
4
|
-
import { encodeUtf8 } from
|
|
3
|
+
import { encodeUtf8 } from "../../utils/index.js";
|
|
5
4
|
|
|
6
5
|
export enum AdbSyncRequestId {
|
|
7
|
-
List =
|
|
8
|
-
|
|
9
|
-
Send =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
16
|
}
|
|
17
17
|
|
|
18
|
-
export const AdbSyncNumberRequest =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
.uint32('arg');
|
|
18
|
+
export const AdbSyncNumberRequest = new Struct({ littleEndian: true })
|
|
19
|
+
.string("id", { length: 4 })
|
|
20
|
+
.uint32("arg");
|
|
22
21
|
|
|
23
|
-
export const AdbSyncDataRequest =
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
export const AdbSyncDataRequest = new Struct({ littleEndian: true })
|
|
23
|
+
.fields(AdbSyncNumberRequest)
|
|
24
|
+
.uint8Array("data", { lengthField: "arg" });
|
|
25
|
+
|
|
26
|
+
export interface AdbSyncWritable {
|
|
27
|
+
write(buffer: Uint8Array): Promise<void>;
|
|
28
|
+
}
|
|
27
29
|
|
|
28
30
|
export async function adbSyncWriteRequest(
|
|
29
|
-
|
|
31
|
+
writable: AdbSyncWritable,
|
|
30
32
|
id: AdbSyncRequestId | string,
|
|
31
33
|
value: number | string | Uint8Array
|
|
32
34
|
): Promise<void> {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
buffer = AdbSyncNumberRequest.serialize({
|
|
35
|
+
if (typeof value === "number") {
|
|
36
|
+
const buffer = AdbSyncNumberRequest.serialize({
|
|
36
37
|
id,
|
|
37
38
|
arg: value,
|
|
38
39
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
await writable.write(buffer);
|
|
41
|
+
} else if (typeof value === "string") {
|
|
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);
|
|
44
48
|
} else {
|
|
45
|
-
|
|
46
|
-
id,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
await writable.write(
|
|
50
|
+
AdbSyncNumberRequest.serialize({ id, arg: value.byteLength })
|
|
51
|
+
);
|
|
52
|
+
await writable.write(value);
|
|
49
53
|
}
|
|
50
|
-
await writer.write(buffer);
|
|
51
54
|
}
|
|
@@ -1,38 +1,41 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
StructAsyncDeserializeStream,
|
|
3
|
+
StructLike,
|
|
4
|
+
StructValueType,
|
|
5
|
+
} from "@yume-chan/struct";
|
|
6
|
+
import Struct from "@yume-chan/struct";
|
|
3
7
|
|
|
4
|
-
import { decodeUtf8 } from
|
|
8
|
+
import { decodeUtf8 } from "../../utils/index.js";
|
|
5
9
|
|
|
6
10
|
export enum AdbSyncResponseId {
|
|
7
|
-
Entry =
|
|
8
|
-
Entry2 =
|
|
9
|
-
Lstat =
|
|
10
|
-
Stat =
|
|
11
|
-
Lstat2 =
|
|
12
|
-
Done =
|
|
13
|
-
Data =
|
|
14
|
-
Ok =
|
|
15
|
-
Fail =
|
|
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",
|
|
16
20
|
}
|
|
17
21
|
|
|
18
|
-
export const AdbSyncFailResponse =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
22
|
+
export const AdbSyncFailResponse = new Struct({ littleEndian: true })
|
|
23
|
+
.uint32("messageLength")
|
|
24
|
+
.string("message", { lengthField: "messageLength" })
|
|
25
|
+
.postDeserialize((object) => {
|
|
26
|
+
throw new Error(object.message);
|
|
27
|
+
});
|
|
25
28
|
|
|
26
29
|
export async function adbSyncReadResponse<T>(
|
|
27
|
-
stream:
|
|
30
|
+
stream: StructAsyncDeserializeStream,
|
|
28
31
|
id: AdbSyncResponseId,
|
|
29
|
-
type: StructLike<T
|
|
32
|
+
type: StructLike<T>
|
|
30
33
|
): Promise<T> {
|
|
31
34
|
const actualId = decodeUtf8(await stream.read(4));
|
|
32
35
|
switch (actualId) {
|
|
33
36
|
case AdbSyncResponseId.Fail:
|
|
34
37
|
await AdbSyncFailResponse.deserialize(stream);
|
|
35
|
-
throw new Error(
|
|
38
|
+
throw new Error("Unreachable");
|
|
36
39
|
case id:
|
|
37
40
|
return await type.deserialize(stream);
|
|
38
41
|
default:
|
|
@@ -40,17 +43,19 @@ export async function adbSyncReadResponse<T>(
|
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
export async function* adbSyncReadResponses<
|
|
44
|
-
|
|
46
|
+
export async function* adbSyncReadResponses<
|
|
47
|
+
T extends Struct<object, PropertyKey, object, any>
|
|
48
|
+
>(
|
|
49
|
+
stream: StructAsyncDeserializeStream,
|
|
45
50
|
id: AdbSyncResponseId,
|
|
46
|
-
type: T
|
|
51
|
+
type: T
|
|
47
52
|
): AsyncGenerator<StructValueType<T>, void, void> {
|
|
48
53
|
while (true) {
|
|
49
54
|
const actualId = decodeUtf8(await stream.read(4));
|
|
50
55
|
switch (actualId) {
|
|
51
56
|
case AdbSyncResponseId.Fail:
|
|
52
57
|
await AdbSyncFailResponse.deserialize(stream);
|
|
53
|
-
throw new Error(
|
|
58
|
+
throw new Error("Unreachable");
|
|
54
59
|
case AdbSyncResponseId.Done:
|
|
55
60
|
// `DONE` responses' size are always same as the request's normal response.
|
|
56
61
|
//
|
|
@@ -62,7 +67,9 @@ export async function* adbSyncReadResponses<T extends Struct<any, any, any, any>
|
|
|
62
67
|
yield await type.deserialize(stream);
|
|
63
68
|
break;
|
|
64
69
|
default:
|
|
65
|
-
throw new Error(
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${actualId}'`
|
|
72
|
+
);
|
|
66
73
|
}
|
|
67
74
|
}
|
|
68
75
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
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 { StructAsyncDeserializeStream } from "@yume-chan/struct";
|
|
11
|
+
|
|
12
|
+
import type { AdbSocket } from "../../index.js";
|
|
13
|
+
import { AutoResetEvent } from "../../index.js";
|
|
14
|
+
|
|
15
|
+
export class AdbSyncSocketLocked implements StructAsyncDeserializeStream {
|
|
16
|
+
private readonly _writer: WritableStreamDefaultWriter<
|
|
17
|
+
Consumable<Uint8Array>
|
|
18
|
+
>;
|
|
19
|
+
private readonly _readable: BufferedReadableStream;
|
|
20
|
+
private readonly _socketLock: AutoResetEvent;
|
|
21
|
+
private readonly _writeLock = new AutoResetEvent();
|
|
22
|
+
private readonly _combiner: BufferCombiner;
|
|
23
|
+
|
|
24
|
+
public constructor(
|
|
25
|
+
writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>,
|
|
26
|
+
readable: BufferedReadableStream,
|
|
27
|
+
bufferSize: number,
|
|
28
|
+
lock: AutoResetEvent
|
|
29
|
+
) {
|
|
30
|
+
this._writer = writer;
|
|
31
|
+
this._readable = readable;
|
|
32
|
+
this._socketLock = lock;
|
|
33
|
+
this._combiner = new BufferCombiner(bufferSize);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private async writeInnerStream(buffer: Uint8Array) {
|
|
37
|
+
await ConsumableWritableStream.write(this._writer, buffer);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public async flush() {
|
|
41
|
+
try {
|
|
42
|
+
await this._writeLock.wait();
|
|
43
|
+
const buffer = this._combiner.flush();
|
|
44
|
+
if (buffer) {
|
|
45
|
+
await this.writeInnerStream(buffer);
|
|
46
|
+
}
|
|
47
|
+
} finally {
|
|
48
|
+
this._writeLock.notifyOne();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public async write(data: Uint8Array) {
|
|
53
|
+
try {
|
|
54
|
+
await this._writeLock.wait();
|
|
55
|
+
for (const buffer of this._combiner.push(data)) {
|
|
56
|
+
await this.writeInnerStream(buffer);
|
|
57
|
+
}
|
|
58
|
+
} finally {
|
|
59
|
+
this._writeLock.notifyOne();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public async read(length: number) {
|
|
64
|
+
await this.flush();
|
|
65
|
+
return await this._readable.read(length);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public release(): void {
|
|
69
|
+
this._combiner.flush();
|
|
70
|
+
this._socketLock.notifyOne();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export class AdbSyncSocket {
|
|
75
|
+
private _lock = new AutoResetEvent();
|
|
76
|
+
private _socket: AdbSocket;
|
|
77
|
+
private _locked: AdbSyncSocketLocked;
|
|
78
|
+
|
|
79
|
+
public constructor(socket: AdbSocket, bufferSize: number) {
|
|
80
|
+
this._socket = socket;
|
|
81
|
+
this._locked = new AdbSyncSocketLocked(
|
|
82
|
+
socket.writable.getWriter(),
|
|
83
|
+
new BufferedReadableStream(socket.readable),
|
|
84
|
+
bufferSize,
|
|
85
|
+
this._lock
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public async lock() {
|
|
90
|
+
await this._lock.wait();
|
|
91
|
+
return this._locked;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public async close() {
|
|
95
|
+
await this._socket.close();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import Struct, { placeholder } from '@yume-chan/struct';
|
|
1
|
+
import Struct, { placeholder } from "@yume-chan/struct";
|
|
3
2
|
|
|
4
|
-
import { AdbSyncRequestId, adbSyncWriteRequest } from
|
|
5
|
-
import {
|
|
3
|
+
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|
4
|
+
import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
|
|
5
|
+
import type { AdbSyncSocket } from "./socket.js";
|
|
6
6
|
|
|
7
7
|
// https://github.com/python/cpython/blob/4e581d64b8aff3e2eda99b12f080c877bb78dfca/Lib/stat.py#L36
|
|
8
8
|
export enum LinuxFileType {
|
|
@@ -24,27 +24,27 @@ export interface AdbSyncStat {
|
|
|
24
24
|
ctime?: bigint;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export const AdbSyncLstatResponse =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
});
|
|
27
|
+
export const AdbSyncLstatResponse = new Struct({ littleEndian: true })
|
|
28
|
+
.int32("mode")
|
|
29
|
+
.int32("size")
|
|
30
|
+
.int32("mtime")
|
|
31
|
+
.extra({
|
|
32
|
+
id: AdbSyncResponseId.Lstat as const,
|
|
33
|
+
get type() {
|
|
34
|
+
return (this.mode >> 12) as LinuxFileType;
|
|
35
|
+
},
|
|
36
|
+
get permission() {
|
|
37
|
+
return this.mode & 0b00001111_11111111;
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
.postDeserialize((object) => {
|
|
41
|
+
if (object.mode === 0 && object.size === 0 && object.mtime === 0) {
|
|
42
|
+
throw new Error("lstat error");
|
|
43
|
+
}
|
|
44
|
+
});
|
|
46
45
|
|
|
47
|
-
export type AdbSyncLstatResponse =
|
|
46
|
+
export type AdbSyncLstatResponse =
|
|
47
|
+
(typeof AdbSyncLstatResponse)["TDeserializeResult"];
|
|
48
48
|
|
|
49
49
|
export enum AdbSyncStatErrorCode {
|
|
50
50
|
SUCCESS = 0,
|
|
@@ -70,60 +70,88 @@ export enum AdbSyncStatErrorCode {
|
|
|
70
70
|
ETXTBSY = 26,
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
export const AdbSyncStatResponse =
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
73
|
+
export const AdbSyncStatResponse = new Struct({ littleEndian: true })
|
|
74
|
+
.uint32("error", placeholder<AdbSyncStatErrorCode>())
|
|
75
|
+
.uint64("dev")
|
|
76
|
+
.uint64("ino")
|
|
77
|
+
.uint32("mode")
|
|
78
|
+
.uint32("nlink")
|
|
79
|
+
.uint32("uid")
|
|
80
|
+
.uint32("gid")
|
|
81
|
+
.uint64("size")
|
|
82
|
+
.uint64("atime")
|
|
83
|
+
.uint64("mtime")
|
|
84
|
+
.uint64("ctime")
|
|
85
|
+
.extra({
|
|
86
|
+
id: AdbSyncResponseId.Stat as const,
|
|
87
|
+
get type() {
|
|
88
|
+
return (this.mode >> 12) as LinuxFileType;
|
|
89
|
+
},
|
|
90
|
+
get permission() {
|
|
91
|
+
return this.mode & 0b00001111_11111111;
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
.postDeserialize((object) => {
|
|
95
|
+
if (object.error) {
|
|
96
|
+
throw new Error(AdbSyncStatErrorCode[object.error]);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
96
99
|
|
|
97
|
-
export type AdbSyncStatResponse =
|
|
100
|
+
export type AdbSyncStatResponse =
|
|
101
|
+
(typeof AdbSyncStatResponse)["TDeserializeResult"];
|
|
98
102
|
|
|
99
103
|
export async function adbSyncLstat(
|
|
100
|
-
|
|
101
|
-
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
104
|
+
socket: AdbSyncSocket,
|
|
102
105
|
path: string,
|
|
103
|
-
v2: boolean
|
|
106
|
+
v2: boolean
|
|
104
107
|
): Promise<AdbSyncStat> {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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();
|
|
119
139
|
}
|
|
120
140
|
}
|
|
121
141
|
|
|
122
142
|
export async function adbSyncStat(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
path: string,
|
|
143
|
+
socket: AdbSyncSocket,
|
|
144
|
+
path: string
|
|
126
145
|
): Promise<AdbSyncStatResponse> {
|
|
127
|
-
await
|
|
128
|
-
|
|
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
|
+
}
|
|
129
157
|
}
|