@yume-chan/adb 0.0.19 → 0.0.21
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 +57 -0
- package/CHANGELOG.md +26 -1
- package/README.md +222 -103
- package/esm/adb.d.ts +28 -45
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +34 -213
- 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.map +1 -1
- package/esm/commands/base.js.map +1 -1
- package/esm/commands/framebuffer.d.ts +9 -0
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +27 -3
- package/esm/commands/framebuffer.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 +2 -2
- package/esm/commands/power.js.map +1 -1
- package/esm/commands/reverse.d.ts +17 -18
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +53 -48
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.d.ts +1 -1
- package/esm/commands/subprocess/command.d.ts.map +1 -1
- package/esm/commands/subprocess/command.js +15 -13
- package/esm/commands/subprocess/command.js.map +1 -1
- package/esm/commands/subprocess/protocols/none.d.ts +3 -8
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js +16 -16
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +3 -9
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +63 -57
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +1 -2
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/sync/list.js +2 -2
- package/esm/commands/sync/push.d.ts +14 -3
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +9 -9
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.js +2 -2
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +5 -3
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +7 -5
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +8 -14
- package/esm/commands/sync/socket.d.ts.map +1 -1
- package/esm/commands/sync/socket.js +35 -32
- package/esm/commands/sync/socket.js.map +1 -1
- package/esm/commands/sync/stat.js +4 -4
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +26 -18
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +36 -25
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts +2 -2
- package/esm/commands/tcpip.d.ts.map +1 -1
- package/esm/commands/tcpip.js +4 -2
- package/esm/commands/tcpip.js.map +1 -1
- package/esm/{auth.d.ts → daemon/auth.d.ts} +12 -11
- package/esm/daemon/auth.d.ts.map +1 -0
- package/esm/{auth.js → daemon/auth.js} +31 -22
- package/esm/daemon/auth.js.map +1 -0
- package/esm/{crypto.d.ts → daemon/crypto.d.ts} +5 -5
- package/esm/daemon/crypto.d.ts.map +1 -0
- package/esm/{crypto.js → daemon/crypto.js} +24 -28
- package/esm/daemon/crypto.js.map +1 -0
- package/esm/{backend.d.ts → daemon/device.d.ts} +2 -2
- 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/{socket → daemon}/dispatcher.d.ts +12 -30
- package/esm/daemon/dispatcher.d.ts.map +1 -0
- package/esm/{socket → daemon}/dispatcher.js +80 -78
- 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} +4 -4
- package/esm/daemon/packet.d.ts.map +1 -0
- package/esm/{packet.js → daemon/packet.js} +2 -2
- package/esm/{packet.js.map → daemon/packet.js.map} +1 -1
- package/esm/{socket → daemon}/socket.d.ts +15 -19
- package/esm/daemon/socket.d.ts.map +1 -0
- package/esm/{socket → daemon}/socket.js +49 -42
- package/esm/daemon/socket.js.map +1 -0
- package/esm/daemon/transport.d.ts +53 -0
- package/esm/daemon/transport.d.ts.map +1 -0
- package/esm/daemon/transport.js +186 -0
- package/esm/daemon/transport.js.map +1 -0
- package/esm/features.js +1 -1
- package/esm/features.js.map +1 -1
- package/esm/index.d.ts +3 -5
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +3 -5
- 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 +328 -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 +1 -2
- package/esm/utils/auto-reset-event.d.ts.map +1 -1
- package/esm/utils/auto-reset-event.js +12 -12
- package/esm/utils/auto-reset-event.js.map +1 -1
- package/esm/utils/base64.js +5 -5
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/conditional-variable.d.ts +1 -2
- package/esm/utils/conditional-variable.d.ts.map +1 -1
- package/esm/utils/conditional-variable.js +10 -10
- package/esm/utils/conditional-variable.js.map +1 -1
- 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 +2 -0
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +2 -0
- 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 +12 -12
- package/src/adb.ts +75 -274
- package/src/banner.ts +82 -0
- package/src/commands/base.ts +1 -1
- package/src/commands/framebuffer.ts +31 -3
- package/src/commands/power.ts +10 -10
- package/src/commands/reverse.ts +77 -82
- package/src/commands/subprocess/command.ts +24 -25
- package/src/commands/subprocess/protocols/none.ts +29 -30
- package/src/commands/subprocess/protocols/shell.ts +87 -89
- package/src/commands/subprocess/protocols/types.ts +1 -2
- package/src/commands/sync/list.ts +7 -7
- package/src/commands/sync/pull.ts +4 -4
- package/src/commands/sync/push.ts +28 -16
- package/src/commands/sync/request.ts +4 -4
- package/src/commands/sync/response.ts +13 -11
- package/src/commands/sync/socket.ts +48 -46
- package/src/commands/sync/stat.ts +5 -5
- package/src/commands/sync/sync.ts +55 -43
- package/src/commands/tcpip.ts +6 -4
- package/src/{auth.ts → daemon/auth.ts} +62 -43
- package/src/{crypto.ts → daemon/crypto.ts} +33 -41
- package/src/{backend.ts → daemon/device.ts} +1 -1
- package/src/{socket → daemon}/dispatcher.ts +103 -109
- package/src/daemon/index.ts +7 -0
- package/src/{packet.ts → daemon/packet.ts} +6 -6
- package/src/{socket → daemon}/socket.ts +77 -67
- package/src/daemon/transport.ts +281 -0
- package/src/index.ts +3 -5
- package/src/server/client.ts +473 -0
- package/src/server/index.ts +2 -0
- package/src/server/transport.ts +77 -0
- package/src/utils/auto-reset-event.ts +16 -16
- package/src/utils/base64.ts +5 -5
- package/src/utils/conditional-variable.ts +14 -14
- package/src/utils/hex.ts +58 -0
- package/src/utils/index.ts +2 -0
- 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.map +0 -1
- package/esm/backend.js +0 -2
- package/esm/backend.js.map +0 -1
- package/esm/commands/install.d.ts +0 -10
- 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/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.map +0 -1
- package/esm/socket/socket.js.map +0 -1
- package/src/socket/index.ts +0 -2
|
@@ -7,91 +7,93 @@ import {
|
|
|
7
7
|
BufferedReadableStream,
|
|
8
8
|
ConsumableWritableStream,
|
|
9
9
|
} from "@yume-chan/stream-extra";
|
|
10
|
-
import type {
|
|
10
|
+
import type { AsyncExactReadable } from "@yume-chan/struct";
|
|
11
11
|
|
|
12
|
-
import type { AdbSocket } from "../../
|
|
13
|
-
import { AutoResetEvent } from "../../index.js";
|
|
12
|
+
import type { AdbSocket } from "../../adb.js";
|
|
13
|
+
import { AutoResetEvent } from "../../utils/index.js";
|
|
14
14
|
|
|
15
|
-
export class AdbSyncSocketLocked implements
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
private readonly _writeLock = new AutoResetEvent();
|
|
22
|
-
private readonly _combiner: BufferCombiner;
|
|
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;
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
get position() {
|
|
23
|
+
return this.#readable.position;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
25
27
|
writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>,
|
|
26
28
|
readable: BufferedReadableStream,
|
|
27
29
|
bufferSize: number,
|
|
28
|
-
lock: AutoResetEvent
|
|
30
|
+
lock: AutoResetEvent,
|
|
29
31
|
) {
|
|
30
|
-
this
|
|
31
|
-
this
|
|
32
|
-
this
|
|
33
|
-
this
|
|
32
|
+
this.#writer = writer;
|
|
33
|
+
this.#readable = readable;
|
|
34
|
+
this.#socketLock = lock;
|
|
35
|
+
this.#combiner = new BufferCombiner(bufferSize);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
await ConsumableWritableStream.write(this
|
|
38
|
+
async #writeInnerStream(buffer: Uint8Array) {
|
|
39
|
+
await ConsumableWritableStream.write(this.#writer, buffer);
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
async flush() {
|
|
41
43
|
try {
|
|
42
|
-
await this.
|
|
43
|
-
const buffer = this.
|
|
44
|
+
await this.#writeLock.wait();
|
|
45
|
+
const buffer = this.#combiner.flush();
|
|
44
46
|
if (buffer) {
|
|
45
|
-
await this
|
|
47
|
+
await this.#writeInnerStream(buffer);
|
|
46
48
|
}
|
|
47
49
|
} finally {
|
|
48
|
-
this.
|
|
50
|
+
this.#writeLock.notifyOne();
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
async write(data: Uint8Array) {
|
|
53
55
|
try {
|
|
54
|
-
await this.
|
|
55
|
-
for (const buffer of this.
|
|
56
|
-
await this
|
|
56
|
+
await this.#writeLock.wait();
|
|
57
|
+
for (const buffer of this.#combiner.push(data)) {
|
|
58
|
+
await this.#writeInnerStream(buffer);
|
|
57
59
|
}
|
|
58
60
|
} finally {
|
|
59
|
-
this.
|
|
61
|
+
this.#writeLock.notifyOne();
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
async readExactly(length: number) {
|
|
64
66
|
await this.flush();
|
|
65
|
-
return await this.
|
|
67
|
+
return await this.#readable.readExactly(length);
|
|
66
68
|
}
|
|
67
69
|
|
|
68
|
-
|
|
69
|
-
this.
|
|
70
|
-
this.
|
|
70
|
+
release(): void {
|
|
71
|
+
this.#combiner.flush();
|
|
72
|
+
this.#socketLock.notifyOne();
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
export class AdbSyncSocket {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
readonly #lock = new AutoResetEvent();
|
|
78
|
+
readonly #socket: AdbSocket;
|
|
79
|
+
readonly #locked: AdbSyncSocketLocked;
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
this
|
|
81
|
-
this
|
|
81
|
+
constructor(socket: AdbSocket, bufferSize: number) {
|
|
82
|
+
this.#socket = socket;
|
|
83
|
+
this.#locked = new AdbSyncSocketLocked(
|
|
82
84
|
socket.writable.getWriter(),
|
|
83
85
|
new BufferedReadableStream(socket.readable),
|
|
84
86
|
bufferSize,
|
|
85
|
-
this
|
|
87
|
+
this.#lock,
|
|
86
88
|
);
|
|
87
89
|
}
|
|
88
90
|
|
|
89
|
-
|
|
90
|
-
await this.
|
|
91
|
-
return this
|
|
91
|
+
async lock() {
|
|
92
|
+
await this.#lock.wait();
|
|
93
|
+
return this.#locked;
|
|
92
94
|
}
|
|
93
95
|
|
|
94
|
-
|
|
95
|
-
await this.
|
|
96
|
+
async close() {
|
|
97
|
+
await this.#socket.close();
|
|
96
98
|
}
|
|
97
99
|
}
|
|
@@ -103,7 +103,7 @@ export type AdbSyncStatResponse =
|
|
|
103
103
|
export async function adbSyncLstat(
|
|
104
104
|
socket: AdbSyncSocket,
|
|
105
105
|
path: string,
|
|
106
|
-
v2: boolean
|
|
106
|
+
v2: boolean,
|
|
107
107
|
): Promise<AdbSyncStat> {
|
|
108
108
|
const locked = await socket.lock();
|
|
109
109
|
try {
|
|
@@ -112,14 +112,14 @@ export async function adbSyncLstat(
|
|
|
112
112
|
return await adbSyncReadResponse(
|
|
113
113
|
locked,
|
|
114
114
|
AdbSyncResponseId.Lstat2,
|
|
115
|
-
AdbSyncStatResponse
|
|
115
|
+
AdbSyncStatResponse,
|
|
116
116
|
);
|
|
117
117
|
} else {
|
|
118
118
|
await adbSyncWriteRequest(locked, AdbSyncRequestId.Lstat, path);
|
|
119
119
|
const response = await adbSyncReadResponse(
|
|
120
120
|
locked,
|
|
121
121
|
AdbSyncResponseId.Lstat,
|
|
122
|
-
AdbSyncLstatResponse
|
|
122
|
+
AdbSyncLstatResponse,
|
|
123
123
|
);
|
|
124
124
|
return {
|
|
125
125
|
mode: response.mode,
|
|
@@ -141,7 +141,7 @@ export async function adbSyncLstat(
|
|
|
141
141
|
|
|
142
142
|
export async function adbSyncStat(
|
|
143
143
|
socket: AdbSyncSocket,
|
|
144
|
-
path: string
|
|
144
|
+
path: string,
|
|
145
145
|
): Promise<AdbSyncStatResponse> {
|
|
146
146
|
const locked = await socket.lock();
|
|
147
147
|
try {
|
|
@@ -149,7 +149,7 @@ export async function adbSyncStat(
|
|
|
149
149
|
return await adbSyncReadResponse(
|
|
150
150
|
locked,
|
|
151
151
|
AdbSyncResponseId.Stat,
|
|
152
|
-
AdbSyncStatResponse
|
|
152
|
+
AdbSyncStatResponse,
|
|
153
153
|
);
|
|
154
154
|
} finally {
|
|
155
155
|
locked.release();
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { AutoDisposable } from "@yume-chan/event";
|
|
2
2
|
import type { Consumable, ReadableStream } from "@yume-chan/stream-extra";
|
|
3
3
|
|
|
4
|
-
import type { Adb } from "../../adb.js";
|
|
4
|
+
import type { Adb, AdbSocket } from "../../adb.js";
|
|
5
5
|
import { AdbFeature } from "../../features.js";
|
|
6
|
-
import type { AdbSocket } from "../../socket/index.js";
|
|
7
6
|
import { escapeArg } from "../subprocess/index.js";
|
|
8
7
|
|
|
9
8
|
import type { AdbSyncEntry } from "./list.js";
|
|
@@ -11,6 +10,7 @@ import { adbSyncOpenDir } from "./list.js";
|
|
|
11
10
|
import { adbSyncPull } from "./pull.js";
|
|
12
11
|
import { adbSyncPush } from "./push.js";
|
|
13
12
|
import { AdbSyncSocket } from "./socket.js";
|
|
13
|
+
import type { AdbSyncStat, LinuxFileType } from "./stat.js";
|
|
14
14
|
import { adbSyncLstat, adbSyncStat } from "./stat.js";
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -32,7 +32,8 @@ export function dirname(path: string): string {
|
|
|
32
32
|
export interface AdbSyncWriteOptions {
|
|
33
33
|
filename: string;
|
|
34
34
|
file: ReadableStream<Consumable<Uint8Array>>;
|
|
35
|
-
|
|
35
|
+
type?: LinuxFileType;
|
|
36
|
+
permission?: number;
|
|
36
37
|
mtime?: number;
|
|
37
38
|
dryRun?: boolean;
|
|
38
39
|
}
|
|
@@ -41,63 +42,78 @@ export class AdbSync extends AutoDisposable {
|
|
|
41
42
|
protected _adb: Adb;
|
|
42
43
|
protected _socket: AdbSyncSocket;
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
readonly #supportsStat: boolean;
|
|
46
|
+
readonly #supportsListV2: boolean;
|
|
47
|
+
readonly #fixedPushMkdir: boolean;
|
|
48
|
+
readonly #supportsSendReceiveV2: boolean;
|
|
49
|
+
readonly #needPushMkdirWorkaround: boolean;
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
return this
|
|
51
|
+
get supportsStat(): boolean {
|
|
52
|
+
return this.#supportsStat;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
return this
|
|
55
|
+
get supportsListV2(): boolean {
|
|
56
|
+
return this.#supportsListV2;
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
return this
|
|
59
|
+
get fixedPushMkdir(): boolean {
|
|
60
|
+
return this.#fixedPushMkdir;
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
return this
|
|
63
|
+
get supportsSendReceiveV2(): boolean {
|
|
64
|
+
return this.#supportsSendReceiveV2;
|
|
64
65
|
}
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
return this
|
|
67
|
+
get needPushMkdirWorkaround(): boolean {
|
|
68
|
+
return this.#needPushMkdirWorkaround;
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
constructor(adb: Adb, socket: AdbSocket) {
|
|
71
72
|
super();
|
|
72
73
|
|
|
73
74
|
this._adb = adb;
|
|
74
75
|
this._socket = new AdbSyncSocket(socket, adb.maxPayloadSize);
|
|
75
76
|
|
|
76
|
-
this
|
|
77
|
-
this
|
|
78
|
-
this
|
|
79
|
-
this
|
|
80
|
-
AdbFeature.SendReceiveV2
|
|
77
|
+
this.#supportsStat = adb.supportsFeature(AdbFeature.StatV2);
|
|
78
|
+
this.#supportsListV2 = adb.supportsFeature(AdbFeature.ListV2);
|
|
79
|
+
this.#fixedPushMkdir = adb.supportsFeature(AdbFeature.FixedPushMkdir);
|
|
80
|
+
this.#supportsSendReceiveV2 = adb.supportsFeature(
|
|
81
|
+
AdbFeature.SendReceiveV2,
|
|
81
82
|
);
|
|
82
83
|
// https://android.googlesource.com/platform/packages/modules/adb/+/91768a57b7138166e0a3d11f79cd55909dda7014/client/file_sync_client.cpp#1361
|
|
83
|
-
this
|
|
84
|
+
this.#needPushMkdirWorkaround =
|
|
84
85
|
this._adb.supportsFeature(AdbFeature.ShellV2) &&
|
|
85
86
|
!this.fixedPushMkdir;
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Gets information of a file or folder.
|
|
91
|
+
*
|
|
92
|
+
* If `path` points to a symbolic link, the returned information is about the link itself (with `type` being `LinuxFileType.Link`).
|
|
93
|
+
*/
|
|
94
|
+
async lstat(path: string): Promise<AdbSyncStat> {
|
|
95
|
+
return await adbSyncLstat(this._socket, path, this.#supportsStat);
|
|
90
96
|
}
|
|
91
97
|
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Gets the information of a file or folder.
|
|
100
|
+
*
|
|
101
|
+
* If `path` points to a symbolic link, it will be resolved and the returned information is about the target (with `type` being `LinuxFileType.File` or `LinuxFileType.Directory`).
|
|
102
|
+
*/
|
|
103
|
+
async stat(path: string) {
|
|
104
|
+
if (!this.#supportsStat) {
|
|
94
105
|
throw new Error("Not supported");
|
|
95
106
|
}
|
|
96
107
|
|
|
97
108
|
return await adbSyncStat(this._socket, path);
|
|
98
109
|
}
|
|
99
110
|
|
|
100
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Checks if `path` is a directory, or a symbolic link to a directory.
|
|
113
|
+
*
|
|
114
|
+
* This uses `lstat` internally, thus works on all Android versions.
|
|
115
|
+
*/
|
|
116
|
+
async isDirectory(path: string): Promise<boolean> {
|
|
101
117
|
try {
|
|
102
118
|
await this.lstat(path + "/");
|
|
103
119
|
return true;
|
|
@@ -106,11 +122,11 @@ export class AdbSync extends AutoDisposable {
|
|
|
106
122
|
}
|
|
107
123
|
}
|
|
108
124
|
|
|
109
|
-
|
|
125
|
+
opendir(path: string): AsyncGenerator<AdbSyncEntry, void, void> {
|
|
110
126
|
return adbSyncOpenDir(this._socket, path, this.supportsListV2);
|
|
111
127
|
}
|
|
112
128
|
|
|
113
|
-
|
|
129
|
+
async readdir(path: string) {
|
|
114
130
|
const results: AdbSyncEntry[] = [];
|
|
115
131
|
for await (const entry of this.opendir(path)) {
|
|
116
132
|
results.push(entry);
|
|
@@ -119,25 +135,21 @@ export class AdbSync extends AutoDisposable {
|
|
|
119
135
|
}
|
|
120
136
|
|
|
121
137
|
/**
|
|
122
|
-
*
|
|
138
|
+
* Reads the content of a file on device.
|
|
123
139
|
*
|
|
124
140
|
* @param filename The full path of the file on device to read.
|
|
125
|
-
* @returns A `ReadableStream` that
|
|
141
|
+
* @returns A `ReadableStream` that contains the file content.
|
|
126
142
|
*/
|
|
127
|
-
|
|
143
|
+
read(filename: string): ReadableStream<Uint8Array> {
|
|
128
144
|
return adbSyncPull(this._socket, filename);
|
|
129
145
|
}
|
|
130
146
|
|
|
131
147
|
/**
|
|
132
|
-
*
|
|
148
|
+
* Writes a file on device. If the file name already exists, it will be overwritten.
|
|
133
149
|
*
|
|
134
|
-
* @param
|
|
135
|
-
* @param file The content to write.
|
|
136
|
-
* @param mode The unix permissions of the file.
|
|
137
|
-
* @param mtime The modified time of the file.
|
|
138
|
-
* @returns A `WritableStream` that writes to the file.
|
|
150
|
+
* @param options The content and options of the file to write.
|
|
139
151
|
*/
|
|
140
|
-
|
|
152
|
+
async write(options: AdbSyncWriteOptions): Promise<void> {
|
|
141
153
|
if (this.needPushMkdirWorkaround) {
|
|
142
154
|
// It may fail if the path is already existed.
|
|
143
155
|
// Ignore the result.
|
|
@@ -156,7 +168,7 @@ export class AdbSync extends AutoDisposable {
|
|
|
156
168
|
});
|
|
157
169
|
}
|
|
158
170
|
|
|
159
|
-
|
|
171
|
+
override async dispose() {
|
|
160
172
|
super.dispose();
|
|
161
173
|
await this._socket.close();
|
|
162
174
|
}
|
package/src/commands/tcpip.ts
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import { AdbCommandBase } from "./base.js";
|
|
2
2
|
|
|
3
3
|
export class AdbTcpIpCommand extends AdbCommandBase {
|
|
4
|
-
|
|
4
|
+
async setPort(port: number): Promise<string> {
|
|
5
5
|
if (port <= 0) {
|
|
6
6
|
throw new Error(`Invalid port ${port}`);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
const output = await this.adb.createSocketAndWait(`tcpip:${port}`);
|
|
10
10
|
if (output !== `restarting in TCP mode port: ${port}\n`) {
|
|
11
|
-
throw new Error(
|
|
11
|
+
throw new Error(output);
|
|
12
12
|
}
|
|
13
|
+
return output;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
async disable(): Promise<string> {
|
|
16
17
|
const output = await this.adb.createSocketAndWait("usb:");
|
|
17
18
|
if (output !== "restarting in USB mode\n") {
|
|
18
|
-
throw new Error(
|
|
19
|
+
throw new Error(output);
|
|
19
20
|
}
|
|
21
|
+
return output;
|
|
20
22
|
}
|
|
21
23
|
}
|
|
@@ -1,28 +1,42 @@
|
|
|
1
1
|
import { PromiseResolver } from "@yume-chan/async";
|
|
2
2
|
import type { Disposable } from "@yume-chan/event";
|
|
3
3
|
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
4
|
+
import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct";
|
|
4
5
|
|
|
5
6
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
calculateBase64EncodedLength,
|
|
8
|
+
encodeBase64,
|
|
9
|
+
encodeUtf8,
|
|
10
|
+
} from "../utils/index.js";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
adbGeneratePublicKey,
|
|
14
|
+
adbGetPublicKeySize,
|
|
15
|
+
rsaSign,
|
|
9
16
|
} from "./crypto.js";
|
|
10
17
|
import type { AdbPacketData } from "./packet.js";
|
|
11
18
|
import { AdbCommand } from "./packet.js";
|
|
12
|
-
import { calculateBase64EncodedLength, encodeBase64 } from "./utils/index.js";
|
|
13
19
|
|
|
14
|
-
export
|
|
20
|
+
export interface AdbPrivateKey {
|
|
21
|
+
/**
|
|
22
|
+
* The private key in PKCS #8 format.
|
|
23
|
+
*/
|
|
24
|
+
buffer: Uint8Array;
|
|
25
|
+
name?: string | undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type AdbKeyIterable =
|
|
29
|
+
| Iterable<AdbPrivateKey>
|
|
30
|
+
| AsyncIterable<AdbPrivateKey>;
|
|
15
31
|
|
|
16
32
|
export interface AdbCredentialStore {
|
|
17
33
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* The returned `Uint8Array` is the private key in PKCS #8 format.
|
|
34
|
+
* Generates and stores a RSA private key with modulus length `2048` and public exponent `65537`.
|
|
21
35
|
*/
|
|
22
|
-
generateKey(): ValueOrPromise<
|
|
36
|
+
generateKey(): ValueOrPromise<AdbPrivateKey>;
|
|
23
37
|
|
|
24
38
|
/**
|
|
25
|
-
* Synchronously or asynchronously
|
|
39
|
+
* Synchronously or asynchronously iterates through all stored RSA private keys.
|
|
26
40
|
*
|
|
27
41
|
* Each call to `iterateKeys` must return a different iterator that iterate through all stored keys.
|
|
28
42
|
*/
|
|
@@ -49,13 +63,13 @@ export interface AdbAuthenticator {
|
|
|
49
63
|
*/
|
|
50
64
|
(
|
|
51
65
|
credentialStore: AdbCredentialStore,
|
|
52
|
-
getNextRequest: () => Promise<AdbPacketData
|
|
66
|
+
getNextRequest: () => Promise<AdbPacketData>,
|
|
53
67
|
): AsyncIterable<AdbPacketData>;
|
|
54
68
|
}
|
|
55
69
|
|
|
56
70
|
export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
|
|
57
71
|
credentialStore: AdbCredentialStore,
|
|
58
|
-
getNextRequest: () => Promise<AdbPacketData
|
|
72
|
+
getNextRequest: () => Promise<AdbPacketData>,
|
|
59
73
|
): AsyncIterable<AdbPacketData> {
|
|
60
74
|
for await (const key of credentialStore.iterateKeys()) {
|
|
61
75
|
const packet = await getNextRequest();
|
|
@@ -64,7 +78,7 @@ export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
|
|
|
64
78
|
return;
|
|
65
79
|
}
|
|
66
80
|
|
|
67
|
-
const signature =
|
|
81
|
+
const signature = rsaSign(key.buffer, packet.payload);
|
|
68
82
|
yield {
|
|
69
83
|
command: AdbCommand.Auth,
|
|
70
84
|
arg0: AdbAuthType.Signature,
|
|
@@ -76,7 +90,7 @@ export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
|
|
|
76
90
|
|
|
77
91
|
export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
|
|
78
92
|
credentialStore: AdbCredentialStore,
|
|
79
|
-
getNextRequest: () => Promise<AdbPacketData
|
|
93
|
+
getNextRequest: () => Promise<AdbPacketData>,
|
|
80
94
|
): AsyncIterable<AdbPacketData> {
|
|
81
95
|
const packet = await getNextRequest();
|
|
82
96
|
|
|
@@ -84,7 +98,7 @@ export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
|
|
|
84
98
|
return;
|
|
85
99
|
}
|
|
86
100
|
|
|
87
|
-
let privateKey:
|
|
101
|
+
let privateKey: AdbPrivateKey | undefined;
|
|
88
102
|
for await (const key of credentialStore.iterateKeys()) {
|
|
89
103
|
privateKey = key;
|
|
90
104
|
break;
|
|
@@ -94,17 +108,27 @@ export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
|
|
|
94
108
|
privateKey = await credentialStore.generateKey();
|
|
95
109
|
}
|
|
96
110
|
|
|
97
|
-
const publicKeyLength =
|
|
111
|
+
const publicKeyLength = adbGetPublicKeySize();
|
|
98
112
|
const [publicKeyBase64Length] =
|
|
99
113
|
calculateBase64EncodedLength(publicKeyLength);
|
|
100
114
|
|
|
115
|
+
const nameBuffer = privateKey.name?.length
|
|
116
|
+
? encodeUtf8(privateKey.name)
|
|
117
|
+
: EMPTY_UINT8_ARRAY;
|
|
101
118
|
const publicKeyBuffer = new Uint8Array(
|
|
102
|
-
publicKeyBase64Length +
|
|
119
|
+
publicKeyBase64Length +
|
|
120
|
+
(nameBuffer.length ? nameBuffer.length + 1 : 0) + // Space character + name
|
|
121
|
+
1, // Null character
|
|
103
122
|
);
|
|
104
123
|
|
|
105
|
-
|
|
124
|
+
adbGeneratePublicKey(privateKey.buffer, publicKeyBuffer);
|
|
106
125
|
encodeBase64(publicKeyBuffer.subarray(0, publicKeyLength), publicKeyBuffer);
|
|
107
126
|
|
|
127
|
+
if (nameBuffer.length) {
|
|
128
|
+
publicKeyBuffer[publicKeyBase64Length] = 0x20;
|
|
129
|
+
publicKeyBuffer.set(nameBuffer, publicKeyBase64Length + 1);
|
|
130
|
+
}
|
|
131
|
+
|
|
108
132
|
yield {
|
|
109
133
|
command: AdbCommand.Auth,
|
|
110
134
|
arg0: AdbAuthType.PublicKey,
|
|
@@ -119,39 +143,34 @@ export const ADB_DEFAULT_AUTHENTICATORS: AdbAuthenticator[] = [
|
|
|
119
143
|
];
|
|
120
144
|
|
|
121
145
|
export class AdbAuthenticationProcessor implements Disposable {
|
|
122
|
-
|
|
146
|
+
readonly authenticators: readonly AdbAuthenticator[];
|
|
123
147
|
|
|
124
|
-
|
|
148
|
+
readonly #credentialStore: AdbCredentialStore;
|
|
125
149
|
|
|
126
|
-
|
|
150
|
+
#pendingRequest = new PromiseResolver<AdbPacketData>();
|
|
151
|
+
#iterator: AsyncIterator<AdbPacketData, void, void> | undefined;
|
|
127
152
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
public constructor(
|
|
153
|
+
constructor(
|
|
131
154
|
authenticators: readonly AdbAuthenticator[],
|
|
132
|
-
credentialStore: AdbCredentialStore
|
|
155
|
+
credentialStore: AdbCredentialStore,
|
|
133
156
|
) {
|
|
134
157
|
this.authenticators = authenticators;
|
|
135
|
-
this
|
|
158
|
+
this.#credentialStore = credentialStore;
|
|
136
159
|
}
|
|
137
160
|
|
|
138
|
-
|
|
139
|
-
return this
|
|
161
|
+
#getNextRequest = (): Promise<AdbPacketData> => {
|
|
162
|
+
return this.#pendingRequest.promise;
|
|
140
163
|
};
|
|
141
164
|
|
|
142
|
-
|
|
143
|
-
AdbPacketData,
|
|
144
|
-
void,
|
|
145
|
-
void
|
|
146
|
-
> {
|
|
165
|
+
async *#invokeAuthenticator(): AsyncGenerator<AdbPacketData, void, void> {
|
|
147
166
|
for (const authenticator of this.authenticators) {
|
|
148
167
|
for await (const packet of authenticator(
|
|
149
|
-
this
|
|
150
|
-
this
|
|
168
|
+
this.#credentialStore,
|
|
169
|
+
this.#getNextRequest,
|
|
151
170
|
)) {
|
|
152
171
|
// If the authenticator yielded a response
|
|
153
172
|
// Prepare `nextRequest` for next authentication request
|
|
154
|
-
this
|
|
173
|
+
this.#pendingRequest = new PromiseResolver();
|
|
155
174
|
|
|
156
175
|
// Yield the response to outer layer
|
|
157
176
|
yield packet;
|
|
@@ -162,14 +181,14 @@ export class AdbAuthenticationProcessor implements Disposable {
|
|
|
162
181
|
}
|
|
163
182
|
}
|
|
164
183
|
|
|
165
|
-
|
|
166
|
-
if (!this
|
|
167
|
-
this
|
|
184
|
+
async process(packet: AdbPacketData): Promise<AdbPacketData> {
|
|
185
|
+
if (!this.#iterator) {
|
|
186
|
+
this.#iterator = this.#invokeAuthenticator();
|
|
168
187
|
}
|
|
169
188
|
|
|
170
|
-
this
|
|
189
|
+
this.#pendingRequest.resolve(packet);
|
|
171
190
|
|
|
172
|
-
const result = await this
|
|
191
|
+
const result = await this.#iterator.next();
|
|
173
192
|
if (result.done) {
|
|
174
193
|
throw new Error("No authenticator can handle the request");
|
|
175
194
|
}
|
|
@@ -177,7 +196,7 @@ export class AdbAuthenticationProcessor implements Disposable {
|
|
|
177
196
|
return result.value;
|
|
178
197
|
}
|
|
179
198
|
|
|
180
|
-
|
|
181
|
-
void this
|
|
199
|
+
dispose() {
|
|
200
|
+
void this.#iterator?.return?.();
|
|
182
201
|
}
|
|
183
202
|
}
|