@yume-chan/adb 0.0.17 → 0.0.18
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 +6 -0
- package/CHANGELOG.md +6 -1
- package/LICENSE +1 -1
- package/esm/adb.d.ts +6 -6
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +55 -35
- package/esm/adb.js.map +1 -1
- package/esm/auth.d.ts +4 -4
- package/esm/auth.d.ts.map +1 -1
- package/esm/auth.js +6 -6
- package/esm/auth.js.map +1 -1
- package/esm/backend.d.ts +3 -3
- package/esm/backend.d.ts.map +1 -1
- package/esm/commands/base.d.ts +2 -2
- package/esm/commands/base.d.ts.map +1 -1
- package/esm/commands/base.js +1 -1
- package/esm/commands/framebuffer.d.ts +7 -7
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +32 -33
- package/esm/commands/framebuffer.js.map +1 -1
- package/esm/commands/install.d.ts +2 -2
- package/esm/commands/install.d.ts.map +1 -1
- package/esm/commands/install.js +12 -6
- package/esm/commands/install.js.map +1 -1
- package/esm/commands/power.d.ts +1 -1
- package/esm/commands/power.d.ts.map +1 -1
- package/esm/commands/power.js +14 -10
- package/esm/commands/power.js.map +1 -1
- package/esm/commands/reverse.d.ts +3 -3
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +14 -12
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.d.ts +2 -2
- package/esm/commands/subprocess/command.d.ts.map +1 -1
- package/esm/commands/subprocess/command.js +14 -16
- package/esm/commands/subprocess/command.js.map +1 -1
- package/esm/commands/subprocess/protocols/none.d.ts +4 -4
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +4 -4
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +23 -15
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +4 -4
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/list.d.ts +6 -6
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +23 -11
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +4 -4
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +12 -11
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +3 -3
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +6 -7
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.d.ts +4 -4
- package/esm/commands/sync/request.d.ts.map +1 -1
- package/esm/commands/sync/request.js +7 -7
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +4 -4
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +7 -7
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/stat.d.ts +5 -5
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +37 -27
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +6 -6
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +20 -19
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/crypto.d.ts.map +1 -1
- package/esm/crypto.js +25 -15
- package/esm/crypto.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 +8 -8
- package/esm/packet.d.ts.map +1 -1
- package/esm/packet.js +14 -12
- package/esm/packet.js.map +1 -1
- package/esm/socket/dispatcher.d.ts +6 -6
- package/esm/socket/dispatcher.d.ts.map +1 -1
- package/esm/socket/dispatcher.js +22 -19
- package/esm/socket/dispatcher.js.map +1 -1
- package/esm/socket/socket.d.ts +4 -4
- package/esm/socket/socket.d.ts.map +1 -1
- package/esm/socket/socket.js +37 -17
- package/esm/socket/socket.js.map +1 -1
- package/esm/utils/auto-reset-event.d.ts +1 -1
- package/esm/utils/auto-reset-event.d.ts.map +1 -1
- package/esm/utils/auto-reset-event.js +2 -2
- package/esm/utils/base64.d.ts.map +1 -1
- package/esm/utils/base64.js +30 -29
- package/esm/utils/base64.js.map +1 -1
- package/package.json +16 -13
- package/src/adb.ts +133 -84
- package/src/auth.ts +27 -19
- package/src/backend.ts +6 -4
- package/src/commands/base.ts +2 -2
- package/src/commands/framebuffer.ts +37 -41
- package/src/commands/install.ts +19 -11
- package/src/commands/power.ts +15 -11
- package/src/commands/reverse.ts +48 -29
- package/src/commands/subprocess/command.ts +24 -21
- package/src/commands/subprocess/protocols/none.ts +4 -3
- package/src/commands/subprocess/protocols/shell.ts +65 -33
- package/src/commands/subprocess/protocols/types.ts +8 -5
- package/src/commands/sync/list.ts +51 -24
- package/src/commands/sync/pull.ts +51 -34
- package/src/commands/sync/push.ts +25 -11
- package/src/commands/sync/request.ts +20 -22
- package/src/commands/sync/response.ts +31 -25
- package/src/commands/sync/stat.ts +78 -55
- package/src/commands/sync/sync.ts +47 -26
- package/src/crypto.ts +60 -32
- package/src/index.ts +9 -10
- package/src/packet.ts +40 -30
- package/src/socket/dispatcher.ts +115 -78
- package/src/socket/socket.ts +68 -27
- package/src/utils/auto-reset-event.ts +3 -3
- package/src/utils/base64.ts +51 -41
- package/tsconfig.build.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import { PromiseResolver } from '@yume-chan/async';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
PushReadableStream,
|
|
4
|
+
StructDeserializeStream,
|
|
5
|
+
StructSerializeStream,
|
|
6
|
+
TransformStream,
|
|
7
|
+
WritableStream,
|
|
8
|
+
pipeFrom,
|
|
9
|
+
type PushReadableStreamController,
|
|
10
|
+
type ReadableStream,
|
|
11
|
+
type WritableStreamDefaultWriter,
|
|
12
|
+
} from "@yume-chan/stream-extra";
|
|
3
13
|
import Struct, { placeholder, type StructValueType } from '@yume-chan/struct';
|
|
4
14
|
|
|
5
|
-
import type
|
|
15
|
+
import { type Adb } from "../../../adb.js";
|
|
6
16
|
import { AdbFeatures } from '../../../features.js';
|
|
7
|
-
import type
|
|
17
|
+
import { type AdbSocket } from "../../../socket/index.js";
|
|
8
18
|
import { encodeUtf8 } from '../../../utils/index.js';
|
|
9
|
-
|
|
19
|
+
|
|
20
|
+
import { type AdbSubprocessProtocol } from "./types.js";
|
|
10
21
|
|
|
11
22
|
export enum AdbShellProtocolId {
|
|
12
23
|
Stdin,
|
|
@@ -56,15 +67,17 @@ class StdoutDeserializeStream extends TransformStream<AdbShellProtocolPacket, Ui
|
|
|
56
67
|
}
|
|
57
68
|
}
|
|
58
69
|
|
|
59
|
-
class MultiplexStream<T>{
|
|
70
|
+
class MultiplexStream<T> {
|
|
60
71
|
private _readable: PushReadableStream<T>;
|
|
61
72
|
private _readableController!: PushReadableStreamController<T>;
|
|
62
|
-
public get readable() {
|
|
73
|
+
public get readable() {
|
|
74
|
+
return this._readable;
|
|
75
|
+
}
|
|
63
76
|
|
|
64
77
|
private _activeCount = 0;
|
|
65
78
|
|
|
66
79
|
constructor() {
|
|
67
|
-
this._readable = new PushReadableStream(controller => {
|
|
80
|
+
this._readable = new PushReadableStream((controller) => {
|
|
68
81
|
this._readableController = controller;
|
|
69
82
|
});
|
|
70
83
|
}
|
|
@@ -77,13 +90,13 @@ class MultiplexStream<T>{
|
|
|
77
90
|
write: async (chunk) => {
|
|
78
91
|
await this._readableController.enqueue(chunk);
|
|
79
92
|
},
|
|
80
|
-
abort:
|
|
93
|
+
abort: () => {
|
|
81
94
|
this._activeCount -= 1;
|
|
82
95
|
if (this._activeCount === 0) {
|
|
83
96
|
this._readableController.close();
|
|
84
97
|
}
|
|
85
98
|
},
|
|
86
|
-
close:
|
|
99
|
+
close: () => {
|
|
87
100
|
this._activeCount -= 1;
|
|
88
101
|
if (this._activeCount === 0) {
|
|
89
102
|
this._readableController.close();
|
|
@@ -108,27 +121,39 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
108
121
|
|
|
109
122
|
public static async pty(adb: Adb, command: string) {
|
|
110
123
|
// TODO: AdbShellSubprocessProtocol: Support setting `XTERM` environment variable
|
|
111
|
-
return new AdbSubprocessShellProtocol(
|
|
124
|
+
return new AdbSubprocessShellProtocol(
|
|
125
|
+
await adb.createSocket(`shell,v2,pty:${command}`)
|
|
126
|
+
);
|
|
112
127
|
}
|
|
113
128
|
|
|
114
129
|
public static async raw(adb: Adb, command: string) {
|
|
115
|
-
return new AdbSubprocessShellProtocol(
|
|
130
|
+
return new AdbSubprocessShellProtocol(
|
|
131
|
+
await adb.createSocket(`shell,v2,raw:${command}`)
|
|
132
|
+
);
|
|
116
133
|
}
|
|
117
134
|
|
|
118
135
|
private readonly _socket: AdbSocket;
|
|
119
136
|
private _socketWriter: WritableStreamDefaultWriter<AdbShellProtocolPacketInit>;
|
|
120
137
|
|
|
121
138
|
private _stdin: WritableStream<Uint8Array>;
|
|
122
|
-
public get stdin() {
|
|
139
|
+
public get stdin() {
|
|
140
|
+
return this._stdin;
|
|
141
|
+
}
|
|
123
142
|
|
|
124
143
|
private _stdout: ReadableStream<Uint8Array>;
|
|
125
|
-
public get stdout() {
|
|
144
|
+
public get stdout() {
|
|
145
|
+
return this._stdout;
|
|
146
|
+
}
|
|
126
147
|
|
|
127
148
|
private _stderr: ReadableStream<Uint8Array>;
|
|
128
|
-
public get stderr() {
|
|
149
|
+
public get stderr() {
|
|
150
|
+
return this._stderr;
|
|
151
|
+
}
|
|
129
152
|
|
|
130
153
|
private readonly _exit = new PromiseResolver<number>();
|
|
131
|
-
public get exit() {
|
|
154
|
+
public get exit() {
|
|
155
|
+
return this._exit.promise;
|
|
156
|
+
}
|
|
132
157
|
|
|
133
158
|
public constructor(socket: AdbSocket) {
|
|
134
159
|
this._socket = socket;
|
|
@@ -141,27 +166,34 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
141
166
|
|
|
142
167
|
const [stdout, stderr] = socket.readable
|
|
143
168
|
.pipeThrough(new StructDeserializeStream(AdbShellProtocolPacket))
|
|
144
|
-
.pipeThrough(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
169
|
+
.pipeThrough(
|
|
170
|
+
new TransformStream<
|
|
171
|
+
AdbShellProtocolPacket,
|
|
172
|
+
AdbShellProtocolPacket
|
|
173
|
+
>({
|
|
174
|
+
transform: (chunk, controller) => {
|
|
175
|
+
if (chunk.id === AdbShellProtocolId.Exit) {
|
|
176
|
+
this._exit.resolve(new Uint8Array(chunk.data)[0]!);
|
|
177
|
+
// We can let `StdoutDeserializeStream` to process `AdbShellProtocolId.Exit`,
|
|
178
|
+
// but since we need this `TransformStream` to capture the exit code anyway,
|
|
179
|
+
// terminating child streams here is killing two birds with one stone.
|
|
180
|
+
controller.terminate();
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
controller.enqueue(chunk);
|
|
184
|
+
},
|
|
185
|
+
})
|
|
186
|
+
)
|
|
157
187
|
.tee();
|
|
158
|
-
this._stdout = stdout
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
188
|
+
this._stdout = stdout.pipeThrough(
|
|
189
|
+
new StdoutDeserializeStream(AdbShellProtocolId.Stdout)
|
|
190
|
+
);
|
|
191
|
+
this._stderr = stderr.pipeThrough(
|
|
192
|
+
new StdoutDeserializeStream(AdbShellProtocolId.Stderr)
|
|
193
|
+
);
|
|
162
194
|
|
|
163
195
|
const multiplexer = new MultiplexStream<AdbShellProtocolPacketInit>();
|
|
164
|
-
multiplexer.readable
|
|
196
|
+
void multiplexer.readable
|
|
165
197
|
.pipeThrough(new StructSerializeStream(AdbShellProtocolPacket))
|
|
166
198
|
.pipeTo(socket.writable);
|
|
167
199
|
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
type ReadableStream,
|
|
3
|
+
type WritableStream,
|
|
4
|
+
} from "@yume-chan/stream-extra";
|
|
5
|
+
import { type ValueOrPromise } from "@yume-chan/struct";
|
|
3
6
|
|
|
4
|
-
import type
|
|
5
|
-
import type
|
|
7
|
+
import { type Adb } from "../../../adb.js";
|
|
8
|
+
import { type AdbSocket } from "../../../socket/index.js";
|
|
6
9
|
|
|
7
10
|
export interface AdbSubprocessProtocol {
|
|
8
11
|
/**
|
|
@@ -56,5 +59,5 @@ export interface AdbSubprocessProtocolConstructor {
|
|
|
56
59
|
raw(adb: Adb, command: string): ValueOrPromise<AdbSubprocessProtocol>;
|
|
57
60
|
|
|
58
61
|
/** Creates a new `AdbShell` by attaching to an exist `AdbSocket` */
|
|
59
|
-
new(socket: AdbSocket): AdbSubprocessProtocol;
|
|
62
|
+
new (socket: AdbSocket): AdbSubprocessProtocol;
|
|
60
63
|
}
|
|
@@ -1,52 +1,79 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
type BufferedReadableStream,
|
|
3
|
+
type WritableStreamDefaultWriter,
|
|
4
|
+
} from "@yume-chan/stream-extra";
|
|
5
|
+
import Struct from "@yume-chan/struct";
|
|
3
6
|
|
|
4
|
-
import { AdbSyncRequestId, adbSyncWriteRequest } from
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
+
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|
8
|
+
import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
|
|
9
|
+
import {
|
|
10
|
+
AdbSyncLstatResponse,
|
|
11
|
+
AdbSyncStatResponse,
|
|
12
|
+
type AdbSyncStat,
|
|
13
|
+
} from "./stat.js";
|
|
7
14
|
|
|
8
15
|
export interface AdbSyncEntry extends AdbSyncStat {
|
|
9
16
|
name: string;
|
|
10
17
|
}
|
|
11
18
|
|
|
12
|
-
export const AdbSyncEntryResponse =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
.extra({ id: AdbSyncResponseId.Entry as const });
|
|
19
|
+
export const AdbSyncEntryResponse = new Struct({ littleEndian: true })
|
|
20
|
+
.fields(AdbSyncLstatResponse)
|
|
21
|
+
.uint32("nameLength")
|
|
22
|
+
.string("name", { lengthField: "nameLength" })
|
|
23
|
+
.extra({ id: AdbSyncResponseId.Entry as const });
|
|
18
24
|
|
|
19
|
-
export type AdbSyncEntryResponse =
|
|
25
|
+
export type AdbSyncEntryResponse =
|
|
26
|
+
typeof AdbSyncEntryResponse["TDeserializeResult"];
|
|
20
27
|
|
|
21
|
-
export const AdbSyncEntry2Response =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
.extra({ id: AdbSyncResponseId.Entry2 as const });
|
|
28
|
+
export const AdbSyncEntry2Response = new Struct({ littleEndian: true })
|
|
29
|
+
.fields(AdbSyncStatResponse)
|
|
30
|
+
.uint32("nameLength")
|
|
31
|
+
.string("name", { lengthField: "nameLength" })
|
|
32
|
+
.extra({ id: AdbSyncResponseId.Entry2 as const });
|
|
27
33
|
|
|
28
|
-
export type AdbSyncEntry2Response =
|
|
34
|
+
export type AdbSyncEntry2Response =
|
|
35
|
+
typeof AdbSyncEntry2Response["TDeserializeResult"];
|
|
29
36
|
|
|
30
37
|
export async function* adbSyncOpenDir(
|
|
31
38
|
stream: BufferedReadableStream,
|
|
32
39
|
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
33
40
|
path: string,
|
|
34
|
-
v2: boolean
|
|
41
|
+
v2: boolean
|
|
35
42
|
): AsyncGenerator<AdbSyncEntry, void, void> {
|
|
36
43
|
if (v2) {
|
|
37
44
|
await adbSyncWriteRequest(writer, AdbSyncRequestId.List2, path);
|
|
38
|
-
|
|
45
|
+
for await (const item of adbSyncReadResponses(
|
|
46
|
+
stream,
|
|
47
|
+
AdbSyncResponseId.Entry2,
|
|
48
|
+
AdbSyncEntry2Response
|
|
49
|
+
)) {
|
|
50
|
+
// `LST2` can return error codes for failed `lstat` calls.
|
|
51
|
+
// `LIST` just ignores them.
|
|
52
|
+
// But they only contain `name` so still pretty useless.
|
|
53
|
+
if (item.error !== 0) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
yield item;
|
|
57
|
+
}
|
|
39
58
|
} else {
|
|
40
59
|
await adbSyncWriteRequest(writer, AdbSyncRequestId.List, path);
|
|
41
|
-
for await (const item of adbSyncReadResponses(
|
|
60
|
+
for await (const item of adbSyncReadResponses(
|
|
61
|
+
stream,
|
|
62
|
+
AdbSyncResponseId.Entry,
|
|
63
|
+
AdbSyncEntryResponse
|
|
64
|
+
)) {
|
|
42
65
|
// Convert to same format as `AdbSyncEntry2Response` for easier consumption.
|
|
43
66
|
// However it will add some overhead.
|
|
44
67
|
yield {
|
|
45
68
|
mode: item.mode,
|
|
46
69
|
size: BigInt(item.size),
|
|
47
70
|
mtime: BigInt(item.mtime),
|
|
48
|
-
get type() {
|
|
49
|
-
|
|
71
|
+
get type() {
|
|
72
|
+
return item.type;
|
|
73
|
+
},
|
|
74
|
+
get permission() {
|
|
75
|
+
return item.permission;
|
|
76
|
+
},
|
|
50
77
|
name: item.name,
|
|
51
78
|
};
|
|
52
79
|
}
|
|
@@ -1,45 +1,62 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
ReadableStream,
|
|
3
|
+
type BufferedReadableStream,
|
|
4
|
+
type WritableStreamDefaultWriter,
|
|
5
|
+
} from "@yume-chan/stream-extra";
|
|
6
|
+
import Struct from "@yume-chan/struct";
|
|
3
7
|
|
|
4
|
-
import { AdbSyncRequestId, adbSyncWriteRequest } from
|
|
5
|
-
import {
|
|
8
|
+
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|
9
|
+
import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
|
|
6
10
|
|
|
7
|
-
export const AdbSyncDataResponse =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
.extra({ id: AdbSyncResponseId.Data as const });
|
|
11
|
+
export const AdbSyncDataResponse = new Struct({ littleEndian: true })
|
|
12
|
+
.uint32("dataLength")
|
|
13
|
+
.uint8Array("data", { lengthField: "dataLength" })
|
|
14
|
+
.extra({ id: AdbSyncResponseId.Data as const });
|
|
12
15
|
|
|
13
|
-
export type AdbSyncDataResponse =
|
|
16
|
+
export type AdbSyncDataResponse =
|
|
17
|
+
typeof AdbSyncDataResponse["TDeserializeResult"];
|
|
14
18
|
|
|
15
19
|
export function adbSyncPull(
|
|
16
20
|
stream: BufferedReadableStream,
|
|
17
21
|
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
18
|
-
path: string
|
|
22
|
+
path: string
|
|
19
23
|
): ReadableStream<Uint8Array> {
|
|
20
24
|
let generator!: AsyncGenerator<AdbSyncDataResponse, void, void>;
|
|
21
|
-
return new ReadableStream<Uint8Array>(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
return new ReadableStream<Uint8Array>(
|
|
26
|
+
{
|
|
27
|
+
async start() {
|
|
28
|
+
// TODO: If `ReadableStream.from(AsyncGenerator)` is added to spec, use it instead.
|
|
29
|
+
await adbSyncWriteRequest(
|
|
30
|
+
writer,
|
|
31
|
+
AdbSyncRequestId.Receive,
|
|
32
|
+
path
|
|
33
|
+
);
|
|
34
|
+
generator = adbSyncReadResponses(
|
|
35
|
+
stream,
|
|
36
|
+
AdbSyncResponseId.Data,
|
|
37
|
+
AdbSyncDataResponse
|
|
38
|
+
);
|
|
39
|
+
},
|
|
40
|
+
async pull(controller) {
|
|
41
|
+
const { done, value } = await generator.next();
|
|
42
|
+
if (done) {
|
|
43
|
+
controller.close();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
controller.enqueue(value.data);
|
|
47
|
+
},
|
|
48
|
+
cancel() {
|
|
49
|
+
generator.return().catch((e) => {
|
|
50
|
+
void e;
|
|
51
|
+
});
|
|
52
|
+
throw new Error(`Sync commands can't be canceled.`);
|
|
53
|
+
},
|
|
26
54
|
},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
},
|
|
35
|
-
cancel() {
|
|
36
|
-
try {
|
|
37
|
-
generator.return();
|
|
38
|
-
} catch { }
|
|
39
|
-
throw new Error(`Sync commands can't be canceled.`);
|
|
40
|
-
},
|
|
41
|
-
}, {
|
|
42
|
-
highWaterMark: 16 * 1024,
|
|
43
|
-
size(chunk) { return chunk.byteLength; }
|
|
44
|
-
});
|
|
55
|
+
{
|
|
56
|
+
highWaterMark: 16 * 1024,
|
|
57
|
+
size(chunk) {
|
|
58
|
+
return chunk.byteLength;
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
);
|
|
45
62
|
}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
ChunkStream,
|
|
3
|
+
WritableStream,
|
|
4
|
+
pipeFrom,
|
|
5
|
+
type BufferedReadableStream,
|
|
6
|
+
type WritableStreamDefaultWriter,
|
|
7
|
+
} from "@yume-chan/stream-extra";
|
|
8
|
+
import Struct from "@yume-chan/struct";
|
|
3
9
|
|
|
4
|
-
import { AdbSyncRequestId, adbSyncWriteRequest } from
|
|
5
|
-
import {
|
|
6
|
-
import { LinuxFileType } from
|
|
10
|
+
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|
11
|
+
import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
|
|
12
|
+
import { LinuxFileType } from "./stat.js";
|
|
7
13
|
|
|
8
|
-
export const AdbSyncOkResponse =
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32(
|
|
15
|
+
"unused"
|
|
16
|
+
);
|
|
11
17
|
|
|
12
18
|
export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024;
|
|
13
19
|
|
|
@@ -17,20 +23,28 @@ export function adbSyncPush(
|
|
|
17
23
|
filename: string,
|
|
18
24
|
mode: number = (LinuxFileType.File << 12) | 0o666,
|
|
19
25
|
mtime: number = (Date.now() / 1000) | 0,
|
|
20
|
-
packetSize: number = ADB_SYNC_MAX_PACKET_SIZE
|
|
26
|
+
packetSize: number = ADB_SYNC_MAX_PACKET_SIZE
|
|
21
27
|
): WritableStream<Uint8Array> {
|
|
22
28
|
return pipeFrom(
|
|
23
29
|
new WritableStream<Uint8Array>({
|
|
24
30
|
async start() {
|
|
25
31
|
const pathAndMode = `${filename},${mode.toString()}`;
|
|
26
|
-
await adbSyncWriteRequest(
|
|
32
|
+
await adbSyncWriteRequest(
|
|
33
|
+
writer,
|
|
34
|
+
AdbSyncRequestId.Send,
|
|
35
|
+
pathAndMode
|
|
36
|
+
);
|
|
27
37
|
},
|
|
28
38
|
async write(chunk) {
|
|
29
39
|
await adbSyncWriteRequest(writer, AdbSyncRequestId.Data, chunk);
|
|
30
40
|
},
|
|
31
41
|
async close() {
|
|
32
42
|
await adbSyncWriteRequest(writer, AdbSyncRequestId.Done, mtime);
|
|
33
|
-
await adbSyncReadResponse(
|
|
43
|
+
await adbSyncReadResponse(
|
|
44
|
+
stream,
|
|
45
|
+
AdbSyncResponseId.Ok,
|
|
46
|
+
AdbSyncOkResponse
|
|
47
|
+
);
|
|
34
48
|
},
|
|
35
49
|
}),
|
|
36
50
|
new ChunkStream(packetSize)
|
|
@@ -1,29 +1,27 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import Struct from
|
|
1
|
+
import { type WritableStreamDefaultWriter } from "@yume-chan/stream-extra";
|
|
2
|
+
import Struct from "@yume-chan/struct";
|
|
3
3
|
|
|
4
|
-
import { encodeUtf8 } from
|
|
4
|
+
import { encodeUtf8 } from "../../utils/index.js";
|
|
5
5
|
|
|
6
6
|
export enum AdbSyncRequestId {
|
|
7
|
-
List =
|
|
8
|
-
List2 =
|
|
9
|
-
Send =
|
|
10
|
-
Lstat =
|
|
11
|
-
Stat =
|
|
12
|
-
Lstat2 =
|
|
13
|
-
Data =
|
|
14
|
-
Done =
|
|
15
|
-
Receive =
|
|
7
|
+
List = "LIST",
|
|
8
|
+
List2 = "LIS2",
|
|
9
|
+
Send = "SEND",
|
|
10
|
+
Lstat = "STAT",
|
|
11
|
+
Stat = "STA2",
|
|
12
|
+
Lstat2 = "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
|
-
.uint8Array('data', { lengthField: 'arg' });
|
|
22
|
+
export const AdbSyncDataRequest = new Struct({ littleEndian: true })
|
|
23
|
+
.fields(AdbSyncNumberRequest)
|
|
24
|
+
.uint8Array("data", { lengthField: "arg" });
|
|
27
25
|
|
|
28
26
|
export async function adbSyncWriteRequest(
|
|
29
27
|
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
@@ -31,12 +29,12 @@ export async function adbSyncWriteRequest(
|
|
|
31
29
|
value: number | string | Uint8Array
|
|
32
30
|
): Promise<void> {
|
|
33
31
|
let buffer: Uint8Array;
|
|
34
|
-
if (typeof value ===
|
|
32
|
+
if (typeof value === "number") {
|
|
35
33
|
buffer = AdbSyncNumberRequest.serialize({
|
|
36
34
|
id,
|
|
37
35
|
arg: value,
|
|
38
36
|
});
|
|
39
|
-
} else if (typeof value ===
|
|
37
|
+
} else if (typeof value === "string") {
|
|
40
38
|
buffer = AdbSyncDataRequest.serialize({
|
|
41
39
|
id,
|
|
42
40
|
data: encodeUtf8(value),
|
|
@@ -1,38 +1,40 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import Struct, {
|
|
1
|
+
import { type BufferedReadableStream } from "@yume-chan/stream-extra";
|
|
2
|
+
import Struct, {
|
|
3
|
+
type StructLike,
|
|
4
|
+
type StructValueType,
|
|
5
|
+
} from "@yume-chan/struct";
|
|
3
6
|
|
|
4
|
-
import { decodeUtf8 } from
|
|
7
|
+
import { decodeUtf8 } from "../../utils/index.js";
|
|
5
8
|
|
|
6
9
|
export enum AdbSyncResponseId {
|
|
7
|
-
Entry =
|
|
8
|
-
Entry2 =
|
|
9
|
-
Lstat =
|
|
10
|
-
Stat =
|
|
11
|
-
Lstat2 =
|
|
12
|
-
Done =
|
|
13
|
-
Data =
|
|
14
|
-
Ok =
|
|
15
|
-
Fail =
|
|
10
|
+
Entry = "DENT",
|
|
11
|
+
Entry2 = "DNT2",
|
|
12
|
+
Lstat = "STAT",
|
|
13
|
+
Stat = "STA2",
|
|
14
|
+
Lstat2 = "LST2",
|
|
15
|
+
Done = "DONE",
|
|
16
|
+
Data = "DATA",
|
|
17
|
+
Ok = "OKAY",
|
|
18
|
+
Fail = "FAIL",
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
export const AdbSyncFailResponse =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
21
|
+
export const AdbSyncFailResponse = new Struct({ littleEndian: true })
|
|
22
|
+
.uint32("messageLength")
|
|
23
|
+
.string("message", { lengthField: "messageLength" })
|
|
24
|
+
.postDeserialize((object) => {
|
|
25
|
+
throw new Error(object.message);
|
|
26
|
+
});
|
|
25
27
|
|
|
26
28
|
export async function adbSyncReadResponse<T>(
|
|
27
29
|
stream: BufferedReadableStream,
|
|
28
30
|
id: AdbSyncResponseId,
|
|
29
|
-
type: StructLike<T
|
|
31
|
+
type: StructLike<T>
|
|
30
32
|
): Promise<T> {
|
|
31
33
|
const actualId = decodeUtf8(await stream.read(4));
|
|
32
34
|
switch (actualId) {
|
|
33
35
|
case AdbSyncResponseId.Fail:
|
|
34
36
|
await AdbSyncFailResponse.deserialize(stream);
|
|
35
|
-
throw new Error(
|
|
37
|
+
throw new Error("Unreachable");
|
|
36
38
|
case id:
|
|
37
39
|
return await type.deserialize(stream);
|
|
38
40
|
default:
|
|
@@ -40,17 +42,19 @@ export async function adbSyncReadResponse<T>(
|
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
export async function* adbSyncReadResponses<
|
|
45
|
+
export async function* adbSyncReadResponses<
|
|
46
|
+
T extends Struct<object, PropertyKey, object, any>
|
|
47
|
+
>(
|
|
44
48
|
stream: BufferedReadableStream,
|
|
45
49
|
id: AdbSyncResponseId,
|
|
46
|
-
type: T
|
|
50
|
+
type: T
|
|
47
51
|
): AsyncGenerator<StructValueType<T>, void, void> {
|
|
48
52
|
while (true) {
|
|
49
53
|
const actualId = decodeUtf8(await stream.read(4));
|
|
50
54
|
switch (actualId) {
|
|
51
55
|
case AdbSyncResponseId.Fail:
|
|
52
56
|
await AdbSyncFailResponse.deserialize(stream);
|
|
53
|
-
throw new Error(
|
|
57
|
+
throw new Error("Unreachable");
|
|
54
58
|
case AdbSyncResponseId.Done:
|
|
55
59
|
// `DONE` responses' size are always same as the request's normal response.
|
|
56
60
|
//
|
|
@@ -62,7 +66,9 @@ export async function* adbSyncReadResponses<T extends Struct<any, any, any, any>
|
|
|
62
66
|
yield await type.deserialize(stream);
|
|
63
67
|
break;
|
|
64
68
|
default:
|
|
65
|
-
throw new Error(
|
|
69
|
+
throw new Error(
|
|
70
|
+
`Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${actualId}'`
|
|
71
|
+
);
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
74
|
}
|