@yume-chan/adb 0.0.16 → 0.0.17
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 +12 -0
- package/CHANGELOG.md +8 -1
- package/esm/adb.d.ts +8 -3
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +11 -6
- package/esm/adb.js.map +1 -1
- package/esm/auth.d.ts.map +1 -1
- package/esm/auth.js.map +1 -1
- package/esm/backend.d.ts +2 -2
- package/esm/backend.d.ts.map +1 -1
- package/esm/commands/base.d.ts.map +1 -1
- package/esm/commands/base.js.map +1 -1
- package/esm/commands/framebuffer.d.ts +17 -1
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +4 -15
- 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 +3 -2
- package/esm/commands/install.js.map +1 -1
- package/esm/commands/power.d.ts +1 -1
- package/esm/commands/power.js +1 -1
- package/esm/commands/reverse.d.ts +3 -3
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +9 -9
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.d.ts +52 -0
- package/esm/commands/subprocess/command.d.ts.map +1 -0
- package/esm/commands/subprocess/command.js +83 -0
- package/esm/commands/subprocess/command.js.map +1 -0
- package/esm/commands/subprocess/index.d.ts +1 -53
- package/esm/commands/subprocess/index.d.ts.map +1 -1
- package/esm/commands/subprocess/index.js +1 -85
- package/esm/commands/subprocess/index.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 +5 -3
- 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 +6 -6
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +7 -7
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/index.d.ts +1 -1
- package/esm/commands/sync/index.d.ts.map +1 -1
- package/esm/commands/sync/index.js +1 -1
- package/esm/commands/sync/index.js.map +1 -1
- package/esm/commands/sync/list.d.ts +2 -2
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +15 -43
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +3 -2
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +15 -17
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +2 -2
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +2 -5
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.d.ts +1 -1
- package/esm/commands/sync/request.d.ts.map +1 -1
- package/esm/commands/sync/request.js +1 -1
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +4 -9
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +32 -23
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/stat.d.ts +3 -3
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +13 -30
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +2 -2
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +7 -5
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/crypto.js +1 -1
- package/esm/crypto.js.map +1 -1
- package/esm/index.d.ts +0 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +0 -1
- package/esm/index.js.map +1 -1
- package/esm/packet.d.ts +1 -1
- package/esm/packet.d.ts.map +1 -1
- package/esm/packet.js +1 -1
- package/esm/packet.js.map +1 -1
- package/esm/socket/dispatcher.d.ts +8 -3
- package/esm/socket/dispatcher.d.ts.map +1 -1
- package/esm/socket/dispatcher.js +9 -4
- package/esm/socket/dispatcher.js.map +1 -1
- package/esm/socket/index.d.ts +1 -1
- package/esm/socket/index.d.ts.map +1 -1
- package/esm/socket/index.js +1 -1
- package/esm/socket/index.js.map +1 -1
- package/esm/socket/socket.d.ts +3 -3
- package/esm/socket/socket.d.ts.map +1 -1
- package/esm/socket/socket.js +3 -3
- package/esm/socket/socket.js.map +1 -1
- package/esm/utils/base64.d.ts +23 -0
- package/esm/utils/base64.d.ts.map +1 -1
- package/esm/utils/base64.js +6 -0
- package/esm/utils/base64.js.map +1 -1
- package/package.json +13 -14
- package/src/adb.ts +12 -7
- package/src/auth.ts +1 -0
- package/src/backend.ts +3 -2
- package/src/commands/base.ts +1 -0
- package/src/commands/framebuffer.ts +21 -16
- package/src/commands/install.ts +6 -4
- package/src/commands/power.ts +1 -1
- package/src/commands/reverse.ts +11 -10
- package/src/commands/subprocess/command.ts +131 -0
- package/src/commands/subprocess/index.ts +1 -137
- package/src/commands/subprocess/protocols/none.ts +9 -6
- package/src/commands/subprocess/protocols/shell.ts +11 -10
- package/src/commands/subprocess/protocols/types.ts +8 -7
- package/src/commands/sync/index.ts +1 -1
- package/src/commands/sync/list.ts +18 -50
- package/src/commands/sync/pull.ts +17 -18
- package/src/commands/sync/push.ts +4 -7
- package/src/commands/sync/request.ts +3 -2
- package/src/commands/sync/response.ts +43 -39
- package/src/commands/sync/stat.ts +17 -39
- package/src/commands/sync/sync.ts +13 -12
- package/src/crypto.ts +1 -1
- package/src/features.ts +1 -1
- package/src/index.ts +0 -1
- package/src/packet.ts +1 -1
- package/src/socket/dispatcher.ts +9 -4
- package/src/socket/index.ts +1 -1
- package/src/socket/socket.ts +5 -4
- package/src/utils/base64.ts +23 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/stream/buffered.d.ts +0 -39
- package/esm/stream/buffered.d.ts.map +0 -1
- package/esm/stream/buffered.js +0 -143
- package/esm/stream/buffered.js.map +0 -1
- package/esm/stream/detect.d.ts +0 -2
- package/esm/stream/detect.d.ts.map +0 -1
- package/esm/stream/detect.js +0 -6
- package/esm/stream/detect.js.map +0 -1
- package/esm/stream/detect.native.d.ts +0 -240
- package/esm/stream/detect.native.d.ts.map +0 -1
- package/esm/stream/detect.native.js +0 -60
- package/esm/stream/detect.native.js.map +0 -1
- package/esm/stream/detect.polyfill.d.ts +0 -18
- package/esm/stream/detect.polyfill.d.ts.map +0 -1
- package/esm/stream/detect.polyfill.js +0 -4
- package/esm/stream/detect.polyfill.js.map +0 -1
- package/esm/stream/index.d.ts +0 -4
- package/esm/stream/index.d.ts.map +0 -1
- package/esm/stream/index.js +0 -4
- package/esm/stream/index.js.map +0 -1
- package/esm/stream/transform.d.ts +0 -124
- package/esm/stream/transform.d.ts.map +0 -1
- package/esm/stream/transform.js +0 -379
- package/esm/stream/transform.js.map +0 -1
- package/src/stream/buffered.ts +0 -168
- package/src/stream/detect.native.ts +0 -362
- package/src/stream/detect.polyfill.ts +0 -22
- package/src/stream/detect.ts +0 -7
- package/src/stream/index.ts +0 -3
- package/src/stream/transform.ts +0 -474
- package/tsconfig.test.json +0 -9
- package/web-streams-polyfill-4.0.0-beta.2.tgz +0 -0
|
@@ -1,139 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import { DecodeUtf8Stream, GatherStringStream } from "../../stream/index.js";
|
|
3
|
-
import { AdbSubprocessNoneProtocol, AdbSubprocessShellProtocol, type AdbSubprocessProtocol, type AdbSubprocessProtocolConstructor } from './protocols/index.js';
|
|
4
|
-
|
|
1
|
+
export * from './command.js';
|
|
5
2
|
export * from './protocols/index.js';
|
|
6
3
|
export * from './utils.js';
|
|
7
|
-
|
|
8
|
-
export interface AdbSubprocessOptions {
|
|
9
|
-
/**
|
|
10
|
-
* A list of `AdbSubprocessProtocolConstructor`s to be used.
|
|
11
|
-
*
|
|
12
|
-
* Different `AdbSubprocessProtocol` has different capabilities, thus requires specific adaptations.
|
|
13
|
-
* Check their documentations for details.
|
|
14
|
-
*
|
|
15
|
-
* The first protocol whose `isSupported` returns `true` will be used.
|
|
16
|
-
* If no `AdbSubprocessProtocol` is supported, an error will be thrown.
|
|
17
|
-
*
|
|
18
|
-
* @default [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol]
|
|
19
|
-
*/
|
|
20
|
-
protocols: AdbSubprocessProtocolConstructor[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const DEFAULT_OPTIONS: AdbSubprocessOptions = {
|
|
24
|
-
protocols: [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol],
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export interface AdbSubprocessWaitResult {
|
|
28
|
-
stdout: string;
|
|
29
|
-
stderr: string;
|
|
30
|
-
exitCode: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class AdbSubprocess {
|
|
34
|
-
public readonly adb: Adb;
|
|
35
|
-
|
|
36
|
-
public constructor(adb: Adb) {
|
|
37
|
-
this.adb = adb;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private async createProtocol(
|
|
41
|
-
mode: 'pty' | 'raw',
|
|
42
|
-
command?: string | string[],
|
|
43
|
-
options?: Partial<AdbSubprocessOptions>
|
|
44
|
-
): Promise<AdbSubprocessProtocol> {
|
|
45
|
-
const { protocols } = { ...DEFAULT_OPTIONS, ...options };
|
|
46
|
-
|
|
47
|
-
let Constructor: AdbSubprocessProtocolConstructor | undefined;
|
|
48
|
-
for (const item of protocols) {
|
|
49
|
-
// It's async so can't use `Array#find`
|
|
50
|
-
if (await item.isSupported(this.adb)) {
|
|
51
|
-
Constructor = item;
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (!Constructor) {
|
|
57
|
-
throw new Error('No specified protocol is supported by the device');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (Array.isArray(command)) {
|
|
61
|
-
command = command.join(' ');
|
|
62
|
-
} else if (command === undefined) {
|
|
63
|
-
// spawn the default shell
|
|
64
|
-
command = '';
|
|
65
|
-
}
|
|
66
|
-
return await Constructor[mode](this.adb, command);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Spawns an executable in PTY (interactive) mode.
|
|
71
|
-
* @param command The command to run. If omitted, the default shell will be spawned.
|
|
72
|
-
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
73
|
-
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
|
74
|
-
*/
|
|
75
|
-
public shell(
|
|
76
|
-
command?: string | string[],
|
|
77
|
-
options?: Partial<AdbSubprocessOptions>
|
|
78
|
-
): Promise<AdbSubprocessProtocol> {
|
|
79
|
-
return this.createProtocol('pty', command, options);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Spawns an executable and pipe the output.
|
|
84
|
-
* @param command The command to run, or an array of strings containing both command and args.
|
|
85
|
-
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
86
|
-
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
|
87
|
-
*/
|
|
88
|
-
public spawn(
|
|
89
|
-
command: string | string[],
|
|
90
|
-
options?: Partial<AdbSubprocessOptions>
|
|
91
|
-
): Promise<AdbSubprocessProtocol> {
|
|
92
|
-
return this.createProtocol('raw', command, options);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Spawns a new process, waits until it exits, and returns the entire output.
|
|
97
|
-
* @param command The command to run
|
|
98
|
-
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
99
|
-
* @returns The entire output of the command
|
|
100
|
-
*/
|
|
101
|
-
public async spawnAndWait(
|
|
102
|
-
command: string | string[],
|
|
103
|
-
options?: Partial<AdbSubprocessOptions>
|
|
104
|
-
): Promise<AdbSubprocessWaitResult> {
|
|
105
|
-
const shell = await this.spawn(command, options);
|
|
106
|
-
|
|
107
|
-
const stdout = new GatherStringStream();
|
|
108
|
-
const stderr = new GatherStringStream();
|
|
109
|
-
|
|
110
|
-
const [, , exitCode] = await Promise.all([
|
|
111
|
-
shell.stdout
|
|
112
|
-
.pipeThrough(new DecodeUtf8Stream())
|
|
113
|
-
.pipeTo(stdout),
|
|
114
|
-
shell.stderr
|
|
115
|
-
.pipeThrough(new DecodeUtf8Stream())
|
|
116
|
-
.pipeTo(stderr),
|
|
117
|
-
shell.exit
|
|
118
|
-
]);
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
stdout: stdout.result,
|
|
122
|
-
stderr: stderr.result,
|
|
123
|
-
exitCode,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Spawns a new process, waits until it exits, and returns the entire output.
|
|
129
|
-
* @param command The command to run
|
|
130
|
-
* @returns The entire output of the command
|
|
131
|
-
*/
|
|
132
|
-
public async spawnAndWaitLegacy(command: string | string[]): Promise<string> {
|
|
133
|
-
const { stdout } = await this.spawnAndWait(
|
|
134
|
-
command,
|
|
135
|
-
{ protocols: [AdbSubprocessNoneProtocol] }
|
|
136
|
-
);
|
|
137
|
-
return stdout;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import type {
|
|
1
|
+
import { DuplexStreamFactory, ReadableStream } from '@yume-chan/stream-extra';
|
|
2
|
+
|
|
3
|
+
import type { Adb } from '../../../adb.js';
|
|
4
|
+
import type { AdbSocket } from '../../../socket/index.js';
|
|
5
|
+
import type { AdbSubprocessProtocol } from './types.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* The legacy shell
|
|
@@ -20,7 +21,7 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
|
20
21
|
|
|
21
22
|
public static async raw(adb: Adb, command: string) {
|
|
22
23
|
// `shell,raw:${command}` also triggers raw mode,
|
|
23
|
-
// But is not supported
|
|
24
|
+
// But is not supported on Android version <7.
|
|
24
25
|
return new AdbSubprocessNoneProtocol(await adb.createSocket(`exec:${command}`));
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -49,6 +50,8 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
|
49
50
|
public constructor(socket: AdbSocket) {
|
|
50
51
|
this.socket = socket;
|
|
51
52
|
|
|
53
|
+
// Link `stdout`, `stderr` and `stdin` together,
|
|
54
|
+
// so closing any of them will close the others.
|
|
52
55
|
this.duplex = new DuplexStreamFactory<Uint8Array, Uint8Array>({
|
|
53
56
|
close: async () => {
|
|
54
57
|
await this.socket.close();
|
|
@@ -61,7 +64,7 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
public resize() {
|
|
64
|
-
// Not supported
|
|
67
|
+
// Not supported, but don't throw.
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
public kill() {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { PromiseResolver } from
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import type {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
1
|
+
import { PromiseResolver } from '@yume-chan/async';
|
|
2
|
+
import { pipeFrom, PushReadableStream, StructDeserializeStream, StructSerializeStream, TransformStream, WritableStream, type PushReadableStreamController, type ReadableStream, type WritableStreamDefaultWriter } from '@yume-chan/stream-extra';
|
|
3
|
+
import Struct, { placeholder, type StructValueType } from '@yume-chan/struct';
|
|
4
|
+
|
|
5
|
+
import type { Adb } from '../../../adb.js';
|
|
6
|
+
import { AdbFeatures } from '../../../features.js';
|
|
7
|
+
import type { AdbSocket } from '../../../socket/index.js';
|
|
8
|
+
import { encodeUtf8 } from '../../../utils/index.js';
|
|
9
|
+
import type { AdbSubprocessProtocol } from './types.js';
|
|
9
10
|
|
|
10
11
|
export enum AdbShellProtocolId {
|
|
11
12
|
Stdin,
|
|
@@ -102,7 +103,7 @@ class MultiplexStream<T>{
|
|
|
102
103
|
*/
|
|
103
104
|
export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
104
105
|
public static isSupported(adb: Adb) {
|
|
105
|
-
return adb.features
|
|
106
|
+
return adb.features.includes(AdbFeatures.ShellV2);
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
public static async pty(adb: Adb, command: string) {
|
|
@@ -178,7 +179,7 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
178
179
|
data: encodeUtf8(
|
|
179
180
|
// The "correct" format is `${rows}x${cols},${x_pixels}x${y_pixels}`
|
|
180
181
|
// However, according to https://linux.die.net/man/4/tty_ioctl
|
|
181
|
-
// `x_pixels` and `y_pixels` are
|
|
182
|
+
// `x_pixels` and `y_pixels` are unused, so always sending `0` should be fine.
|
|
182
183
|
`${rows}x${cols},0x0\0`
|
|
183
184
|
),
|
|
184
185
|
});
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
import type {
|
|
1
|
+
import type { ReadableStream, WritableStream } from '@yume-chan/stream-extra';
|
|
2
|
+
import type { ValueOrPromise } from '@yume-chan/struct';
|
|
3
|
+
|
|
4
|
+
import type { Adb } from '../../../adb.js';
|
|
5
|
+
import type { AdbSocket } from '../../../socket/index.js';
|
|
5
6
|
|
|
6
7
|
export interface AdbSubprocessProtocol {
|
|
7
8
|
/**
|
|
8
|
-
* A WritableStream that writes to the `stdin`
|
|
9
|
+
* A WritableStream that writes to the `stdin` stream.
|
|
9
10
|
*/
|
|
10
11
|
readonly stdin: WritableStream<Uint8Array>;
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
* The `stdout`
|
|
14
|
+
* The `stdout` stream of the process.
|
|
14
15
|
*/
|
|
15
16
|
readonly stdout: ReadableStream<Uint8Array>;
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
|
-
* The `stderr`
|
|
19
|
+
* The `stderr` stream of the process.
|
|
19
20
|
*
|
|
20
21
|
* Note: Some `AdbSubprocessProtocol` doesn't separate `stdout` and `stderr`,
|
|
21
22
|
* All output will be sent to `stdout`.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { BufferedReadableStream, WritableStreamDefaultWriter } from '@yume-chan/stream-extra';
|
|
1
2
|
import Struct from '@yume-chan/struct';
|
|
2
|
-
|
|
3
|
+
|
|
3
4
|
import { AdbSyncRequestId, adbSyncWriteRequest } from './request.js';
|
|
4
|
-
import {
|
|
5
|
+
import { adbSyncReadResponses, AdbSyncResponseId } from './response.js';
|
|
5
6
|
import { AdbSyncLstatResponse, AdbSyncStatResponse, type AdbSyncStat } from './stat.js';
|
|
6
7
|
|
|
7
8
|
export interface AdbSyncEntry extends AdbSyncStat {
|
|
@@ -26,61 +27,28 @@ export const AdbSyncEntry2Response =
|
|
|
26
27
|
|
|
27
28
|
export type AdbSyncEntry2Response = typeof AdbSyncEntry2Response['TDeserializeResult'];
|
|
28
29
|
|
|
29
|
-
const LIST_V1_RESPONSE_TYPES = {
|
|
30
|
-
[AdbSyncResponseId.Entry]: AdbSyncEntryResponse,
|
|
31
|
-
[AdbSyncResponseId.Done]: new AdbSyncDoneResponse(AdbSyncEntryResponse.size),
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const LIST_V2_RESPONSE_TYPES = {
|
|
35
|
-
[AdbSyncResponseId.Entry2]: AdbSyncEntry2Response,
|
|
36
|
-
[AdbSyncResponseId.Done]: new AdbSyncDoneResponse(AdbSyncEntry2Response.size),
|
|
37
|
-
};
|
|
38
|
-
|
|
39
30
|
export async function* adbSyncOpenDir(
|
|
40
|
-
stream:
|
|
31
|
+
stream: BufferedReadableStream,
|
|
41
32
|
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
42
33
|
path: string,
|
|
43
34
|
v2: boolean,
|
|
44
35
|
): AsyncGenerator<AdbSyncEntry, void, void> {
|
|
45
|
-
let requestId: AdbSyncRequestId.List | AdbSyncRequestId.List2;
|
|
46
|
-
let responseType: typeof LIST_V1_RESPONSE_TYPES | typeof LIST_V2_RESPONSE_TYPES;
|
|
47
|
-
|
|
48
36
|
if (v2) {
|
|
49
|
-
|
|
50
|
-
|
|
37
|
+
await adbSyncWriteRequest(writer, AdbSyncRequestId.List2, path);
|
|
38
|
+
yield* adbSyncReadResponses(stream, AdbSyncResponseId.Entry2, AdbSyncEntry2Response);
|
|
51
39
|
} else {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
size: BigInt(response.size),
|
|
65
|
-
mtime: BigInt(response.mtime),
|
|
66
|
-
get type() { return response.type; },
|
|
67
|
-
get permission() { return response.permission; },
|
|
68
|
-
name: response.name,
|
|
69
|
-
};
|
|
70
|
-
break;
|
|
71
|
-
case AdbSyncResponseId.Entry2:
|
|
72
|
-
// `LST2` can return error codes for failed `lstat` calls.
|
|
73
|
-
// `LIST` just ignores them.
|
|
74
|
-
// But they only contain `name` so still pretty useless.
|
|
75
|
-
if (response.error !== 0) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
yield response;
|
|
79
|
-
break;
|
|
80
|
-
case AdbSyncResponseId.Done:
|
|
81
|
-
return;
|
|
82
|
-
default:
|
|
83
|
-
throw new Error('Unexpected response id');
|
|
40
|
+
await adbSyncWriteRequest(writer, AdbSyncRequestId.List, path);
|
|
41
|
+
for await (const item of adbSyncReadResponses(stream, AdbSyncResponseId.Entry, AdbSyncEntryResponse)) {
|
|
42
|
+
// Convert to same format as `AdbSyncEntry2Response` for easier consumption.
|
|
43
|
+
// However it will add some overhead.
|
|
44
|
+
yield {
|
|
45
|
+
mode: item.mode,
|
|
46
|
+
size: BigInt(item.size),
|
|
47
|
+
mtime: BigInt(item.mtime),
|
|
48
|
+
get type() { return item.type; },
|
|
49
|
+
get permission() { return item.permission; },
|
|
50
|
+
name: item.name,
|
|
51
|
+
};
|
|
84
52
|
}
|
|
85
53
|
}
|
|
86
54
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { BufferedReadableStream, ReadableStream, WritableStreamDefaultWriter } from '@yume-chan/stream-extra';
|
|
1
2
|
import Struct from '@yume-chan/struct';
|
|
2
|
-
|
|
3
|
+
|
|
3
4
|
import { AdbSyncRequestId, adbSyncWriteRequest } from './request.js';
|
|
4
|
-
import {
|
|
5
|
+
import { adbSyncReadResponses, AdbSyncResponseId } from './response.js';
|
|
5
6
|
|
|
6
7
|
export const AdbSyncDataResponse =
|
|
7
8
|
new Struct({ littleEndian: true })
|
|
@@ -9,35 +10,33 @@ export const AdbSyncDataResponse =
|
|
|
9
10
|
.uint8Array('data', { lengthField: 'dataLength' })
|
|
10
11
|
.extra({ id: AdbSyncResponseId.Data as const });
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
[AdbSyncResponseId.Data]: AdbSyncDataResponse,
|
|
14
|
-
[AdbSyncResponseId.Done]: new AdbSyncDoneResponse(AdbSyncDataResponse.size),
|
|
15
|
-
};
|
|
13
|
+
export type AdbSyncDataResponse = typeof AdbSyncDataResponse['TDeserializeResult'];
|
|
16
14
|
|
|
17
15
|
export function adbSyncPull(
|
|
18
|
-
stream:
|
|
16
|
+
stream: BufferedReadableStream,
|
|
19
17
|
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
20
18
|
path: string,
|
|
21
19
|
): ReadableStream<Uint8Array> {
|
|
20
|
+
let generator!: AsyncGenerator<AdbSyncDataResponse, void, void>;
|
|
22
21
|
return new ReadableStream<Uint8Array>({
|
|
23
22
|
async start() {
|
|
23
|
+
// TODO: If `ReadableStream.from(AsyncGenerator)` is added to spec, use it instead.
|
|
24
24
|
await adbSyncWriteRequest(writer, AdbSyncRequestId.Receive, path);
|
|
25
|
+
generator = adbSyncReadResponses(stream, AdbSyncResponseId.Data, AdbSyncDataResponse);
|
|
25
26
|
},
|
|
26
27
|
async pull(controller) {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
break;
|
|
32
|
-
case AdbSyncResponseId.Done:
|
|
33
|
-
controller.close();
|
|
34
|
-
break;
|
|
35
|
-
default:
|
|
36
|
-
throw new Error('Unexpected response id');
|
|
28
|
+
const { done, value } = await generator.next();
|
|
29
|
+
if (done) {
|
|
30
|
+
controller.close();
|
|
31
|
+
return;
|
|
37
32
|
}
|
|
33
|
+
controller.enqueue(value.data);
|
|
38
34
|
},
|
|
39
35
|
cancel() {
|
|
40
|
-
|
|
36
|
+
try {
|
|
37
|
+
generator.return();
|
|
38
|
+
} catch { }
|
|
39
|
+
throw new Error(`Sync commands can't be canceled.`);
|
|
41
40
|
},
|
|
42
41
|
}, {
|
|
43
42
|
highWaterMark: 16 * 1024,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { BufferedReadableStream, ChunkStream, pipeFrom, WritableStream, WritableStreamDefaultWriter } from '@yume-chan/stream-extra';
|
|
1
2
|
import Struct from '@yume-chan/struct';
|
|
2
|
-
|
|
3
|
+
|
|
3
4
|
import { AdbSyncRequestId, adbSyncWriteRequest } from './request.js';
|
|
4
5
|
import { adbSyncReadResponse, AdbSyncResponseId } from './response.js';
|
|
5
6
|
import { LinuxFileType } from './stat.js';
|
|
@@ -8,14 +9,10 @@ export const AdbSyncOkResponse =
|
|
|
8
9
|
new Struct({ littleEndian: true })
|
|
9
10
|
.uint32('unused');
|
|
10
11
|
|
|
11
|
-
const ResponseTypes = {
|
|
12
|
-
[AdbSyncResponseId.Ok]: AdbSyncOkResponse,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
12
|
export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024;
|
|
16
13
|
|
|
17
14
|
export function adbSyncPush(
|
|
18
|
-
stream:
|
|
15
|
+
stream: BufferedReadableStream,
|
|
19
16
|
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
20
17
|
filename: string,
|
|
21
18
|
mode: number = (LinuxFileType.File << 12) | 0o666,
|
|
@@ -33,7 +30,7 @@ export function adbSyncPush(
|
|
|
33
30
|
},
|
|
34
31
|
async close() {
|
|
35
32
|
await adbSyncWriteRequest(writer, AdbSyncRequestId.Done, mtime);
|
|
36
|
-
await adbSyncReadResponse(stream,
|
|
33
|
+
await adbSyncReadResponse(stream, AdbSyncResponseId.Ok, AdbSyncOkResponse);
|
|
37
34
|
},
|
|
38
35
|
}),
|
|
39
36
|
new ChunkStream(packetSize)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { WritableStreamDefaultWriter } from '@yume-chan/stream-extra';
|
|
1
2
|
import Struct from '@yume-chan/struct';
|
|
2
|
-
|
|
3
|
-
import { encodeUtf8 } from
|
|
3
|
+
|
|
4
|
+
import { encodeUtf8 } from '../../utils/index.js';
|
|
4
5
|
|
|
5
6
|
export enum AdbSyncRequestId {
|
|
6
7
|
List = 'LIST',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
1
|
+
import type { BufferedReadableStream } from '@yume-chan/stream-extra';
|
|
2
|
+
import Struct, { StructValueType, type StructLike } from '@yume-chan/struct';
|
|
3
|
+
|
|
4
|
+
import { decodeUtf8 } from '../../utils/index.js';
|
|
4
5
|
|
|
5
6
|
export enum AdbSyncResponseId {
|
|
6
7
|
Entry = 'DENT',
|
|
@@ -14,25 +15,6 @@ export enum AdbSyncResponseId {
|
|
|
14
15
|
Fail = 'FAIL',
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
// DONE responses' size are always same as the request's normal response.
|
|
18
|
-
// For example DONE responses for LIST requests are 16 bytes (same as DENT responses),
|
|
19
|
-
// but DONE responses for STAT requests are 12 bytes (same as STAT responses)
|
|
20
|
-
// So we need to know responses' size in advance.
|
|
21
|
-
export class AdbSyncDoneResponse implements StructLike<AdbSyncDoneResponse> {
|
|
22
|
-
private length: number;
|
|
23
|
-
|
|
24
|
-
public readonly id = AdbSyncResponseId.Done;
|
|
25
|
-
|
|
26
|
-
public constructor(length: number) {
|
|
27
|
-
this.length = length;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public async deserialize(stream: StructAsyncDeserializeStream): Promise<this> {
|
|
31
|
-
await stream.read(this.length);
|
|
32
|
-
return this;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
18
|
export const AdbSyncFailResponse =
|
|
37
19
|
new Struct({ littleEndian: true })
|
|
38
20
|
.uint32('messageLength')
|
|
@@ -41,24 +23,46 @@ export const AdbSyncFailResponse =
|
|
|
41
23
|
throw new Error(object.message);
|
|
42
24
|
});
|
|
43
25
|
|
|
44
|
-
export async function adbSyncReadResponse<T
|
|
45
|
-
stream:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
26
|
+
export async function adbSyncReadResponse<T>(
|
|
27
|
+
stream: BufferedReadableStream,
|
|
28
|
+
id: AdbSyncResponseId,
|
|
29
|
+
type: StructLike<T>,
|
|
30
|
+
): Promise<T> {
|
|
31
|
+
const actualId = decodeUtf8(await stream.read(4));
|
|
32
|
+
switch (actualId) {
|
|
33
|
+
case AdbSyncResponseId.Fail:
|
|
34
|
+
await AdbSyncFailResponse.deserialize(stream);
|
|
35
|
+
throw new Error('Unreachable');
|
|
36
|
+
case id:
|
|
37
|
+
return await type.deserialize(stream);
|
|
38
|
+
default:
|
|
39
|
+
throw new Error(`Expected '${id}', but got '${actualId}'`);
|
|
57
40
|
}
|
|
41
|
+
}
|
|
58
42
|
|
|
59
|
-
|
|
60
|
-
|
|
43
|
+
export async function* adbSyncReadResponses<T extends Struct<any, any, any, any>>(
|
|
44
|
+
stream: BufferedReadableStream,
|
|
45
|
+
id: AdbSyncResponseId,
|
|
46
|
+
type: T,
|
|
47
|
+
): AsyncGenerator<StructValueType<T>, void, void> {
|
|
48
|
+
while (true) {
|
|
49
|
+
const actualId = decodeUtf8(await stream.read(4));
|
|
50
|
+
switch (actualId) {
|
|
51
|
+
case AdbSyncResponseId.Fail:
|
|
52
|
+
await AdbSyncFailResponse.deserialize(stream);
|
|
53
|
+
throw new Error('Unreachable');
|
|
54
|
+
case AdbSyncResponseId.Done:
|
|
55
|
+
// `DONE` responses' size are always same as the request's normal response.
|
|
56
|
+
//
|
|
57
|
+
// For example, `DONE` responses for `LIST` requests are 16 bytes (same as `DENT` responses),
|
|
58
|
+
// but `DONE` responses for `STAT` requests are 12 bytes (same as `STAT` responses).
|
|
59
|
+
await stream.read(type.size);
|
|
60
|
+
return;
|
|
61
|
+
case id:
|
|
62
|
+
yield await type.deserialize(stream);
|
|
63
|
+
break;
|
|
64
|
+
default:
|
|
65
|
+
throw new Error(`Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${actualId}'`);
|
|
66
|
+
}
|
|
61
67
|
}
|
|
62
|
-
|
|
63
|
-
throw new Error(`Expected '${Object.keys(types).join(', ')}', but got '${id}'`);
|
|
64
68
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { BufferedReadableStream, WritableStreamDefaultWriter } from '@yume-chan/stream-extra';
|
|
1
2
|
import Struct, { placeholder } from '@yume-chan/struct';
|
|
2
|
-
|
|
3
|
+
|
|
3
4
|
import { AdbSyncRequestId, adbSyncWriteRequest } from './request.js';
|
|
4
5
|
import { adbSyncReadResponse, AdbSyncResponseId } from './response.js';
|
|
5
6
|
|
|
@@ -95,57 +96,34 @@ export const AdbSyncStatResponse =
|
|
|
95
96
|
|
|
96
97
|
export type AdbSyncStatResponse = typeof AdbSyncStatResponse['TDeserializeResult'];
|
|
97
98
|
|
|
98
|
-
const STAT_RESPONSE_TYPES = {
|
|
99
|
-
[AdbSyncResponseId.Stat]: AdbSyncStatResponse,
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const LSTAT_RESPONSE_TYPES = {
|
|
103
|
-
[AdbSyncResponseId.Lstat]: AdbSyncLstatResponse,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const LSTAT_V2_RESPONSE_TYPES = {
|
|
107
|
-
[AdbSyncResponseId.Lstat2]: AdbSyncStatResponse,
|
|
108
|
-
};
|
|
109
|
-
|
|
110
99
|
export async function adbSyncLstat(
|
|
111
|
-
stream:
|
|
100
|
+
stream: BufferedReadableStream,
|
|
112
101
|
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
113
102
|
path: string,
|
|
114
103
|
v2: boolean,
|
|
115
104
|
): Promise<AdbSyncStat> {
|
|
116
|
-
let requestId: AdbSyncRequestId.Lstat | AdbSyncRequestId.Lstat2;
|
|
117
|
-
let responseType: typeof LSTAT_RESPONSE_TYPES | typeof LSTAT_V2_RESPONSE_TYPES;
|
|
118
|
-
|
|
119
105
|
if (v2) {
|
|
120
|
-
|
|
121
|
-
|
|
106
|
+
await adbSyncWriteRequest(writer, AdbSyncRequestId.Lstat2, path);
|
|
107
|
+
return await adbSyncReadResponse(stream, AdbSyncResponseId.Lstat2, AdbSyncStatResponse);
|
|
122
108
|
} else {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
mode: response.mode,
|
|
134
|
-
size: BigInt(response.size),
|
|
135
|
-
mtime: BigInt(response.mtime),
|
|
136
|
-
get type() { return response.type; },
|
|
137
|
-
get permission() { return response.permission; },
|
|
138
|
-
};
|
|
139
|
-
default:
|
|
140
|
-
return response;
|
|
109
|
+
await adbSyncWriteRequest(writer, AdbSyncRequestId.Lstat, path);
|
|
110
|
+
const response = await adbSyncReadResponse(stream, AdbSyncResponseId.Lstat, AdbSyncLstatResponse);
|
|
111
|
+
return {
|
|
112
|
+
mode: response.mode,
|
|
113
|
+
// Convert to `BigInt` to make it compatible with `AdbSyncStatResponse`
|
|
114
|
+
size: BigInt(response.size),
|
|
115
|
+
mtime: BigInt(response.mtime),
|
|
116
|
+
get type() { return response.type; },
|
|
117
|
+
get permission() { return response.permission; },
|
|
118
|
+
};
|
|
141
119
|
}
|
|
142
120
|
}
|
|
143
121
|
|
|
144
122
|
export async function adbSyncStat(
|
|
145
|
-
stream:
|
|
123
|
+
stream: BufferedReadableStream,
|
|
146
124
|
writer: WritableStreamDefaultWriter<Uint8Array>,
|
|
147
125
|
path: string,
|
|
148
126
|
): Promise<AdbSyncStatResponse> {
|
|
149
127
|
await adbSyncWriteRequest(writer, AdbSyncRequestId.Stat, path);
|
|
150
|
-
return await adbSyncReadResponse(stream,
|
|
128
|
+
return await adbSyncReadResponse(stream, AdbSyncResponseId.Stat, AdbSyncStatResponse);
|
|
151
129
|
}
|