@yume-chan/adb 0.0.18 → 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.
Files changed (164) hide show
  1. package/CHANGELOG.json +21 -0
  2. package/CHANGELOG.md +11 -1
  3. package/esm/adb.d.ts +63 -60
  4. package/esm/adb.d.ts.map +1 -1
  5. package/esm/adb.js +257 -249
  6. package/esm/adb.js.map +1 -1
  7. package/esm/auth.d.ts +51 -51
  8. package/esm/auth.d.ts.map +1 -1
  9. package/esm/auth.js +95 -96
  10. package/esm/auth.js.map +1 -1
  11. package/esm/backend.d.ts +8 -8
  12. package/esm/backend.d.ts.map +1 -1
  13. package/esm/backend.js +1 -1
  14. package/esm/commands/base.d.ts +6 -6
  15. package/esm/commands/base.d.ts.map +1 -1
  16. package/esm/commands/base.js +8 -8
  17. package/esm/commands/framebuffer.d.ts +53 -53
  18. package/esm/commands/framebuffer.d.ts.map +1 -1
  19. package/esm/commands/framebuffer.js +46 -46
  20. package/esm/commands/framebuffer.js.map +1 -1
  21. package/esm/commands/index.d.ts +7 -8
  22. package/esm/commands/index.d.ts.map +1 -1
  23. package/esm/commands/index.js +7 -8
  24. package/esm/commands/index.js.map +1 -1
  25. package/esm/commands/install.d.ts +9 -3
  26. package/esm/commands/install.d.ts.map +1 -1
  27. package/esm/commands/install.js +26 -26
  28. package/esm/commands/install.js.map +1 -1
  29. package/esm/commands/power.d.ts +22 -22
  30. package/esm/commands/power.js +48 -48
  31. package/esm/commands/reverse.d.ts +41 -28
  32. package/esm/commands/reverse.d.ts.map +1 -1
  33. package/esm/commands/reverse.js +125 -100
  34. package/esm/commands/reverse.js.map +1 -1
  35. package/esm/commands/subprocess/command.d.ts +57 -51
  36. package/esm/commands/subprocess/command.d.ts.map +1 -1
  37. package/esm/commands/subprocess/command.js +86 -80
  38. package/esm/commands/subprocess/command.js.map +1 -1
  39. package/esm/commands/subprocess/index.d.ts +3 -3
  40. package/esm/commands/subprocess/index.js +3 -3
  41. package/esm/commands/subprocess/protocols/index.d.ts +3 -3
  42. package/esm/commands/subprocess/protocols/index.js +3 -3
  43. package/esm/commands/subprocess/protocols/none.d.ts +35 -35
  44. package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
  45. package/esm/commands/subprocess/protocols/none.js +65 -55
  46. package/esm/commands/subprocess/protocols/none.js.map +1 -1
  47. package/esm/commands/subprocess/protocols/shell.d.ts +39 -38
  48. package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
  49. package/esm/commands/subprocess/protocols/shell.js +166 -162
  50. package/esm/commands/subprocess/protocols/shell.js.map +1 -1
  51. package/esm/commands/subprocess/protocols/types.d.ts +49 -49
  52. package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
  53. package/esm/commands/subprocess/protocols/types.js +1 -1
  54. package/esm/commands/subprocess/utils.d.ts +1 -1
  55. package/esm/commands/subprocess/utils.js +18 -18
  56. package/esm/commands/sync/index.d.ts +8 -7
  57. package/esm/commands/sync/index.d.ts.map +1 -1
  58. package/esm/commands/sync/index.js +8 -7
  59. package/esm/commands/sync/index.js.map +1 -1
  60. package/esm/commands/sync/list.d.ts +42 -40
  61. package/esm/commands/sync/list.d.ts.map +1 -1
  62. package/esm/commands/sync/list.js +67 -47
  63. package/esm/commands/sync/list.js.map +1 -1
  64. package/esm/commands/sync/pull.d.ts +13 -11
  65. package/esm/commands/sync/pull.d.ts.map +1 -1
  66. package/esm/commands/sync/pull.js +35 -37
  67. package/esm/commands/sync/pull.js.map +1 -1
  68. package/esm/commands/sync/push.d.ts +46 -7
  69. package/esm/commands/sync/push.d.ts.map +1 -1
  70. package/esm/commands/sync/push.js +89 -22
  71. package/esm/commands/sync/push.js.map +1 -1
  72. package/esm/commands/sync/request.d.ts +26 -23
  73. package/esm/commands/sync/request.d.ts.map +1 -1
  74. package/esm/commands/sync/request.js +40 -42
  75. package/esm/commands/sync/request.js.map +1 -1
  76. package/esm/commands/sync/response.d.ts +19 -19
  77. package/esm/commands/sync/response.d.ts.map +1 -1
  78. package/esm/commands/sync/response.js +54 -54
  79. package/esm/commands/sync/response.js.map +1 -1
  80. package/esm/commands/sync/socket.d.ts +27 -0
  81. package/esm/commands/sync/socket.d.ts.map +1 -0
  82. package/esm/commands/sync/socket.js +66 -0
  83. package/esm/commands/sync/socket.js.map +1 -0
  84. package/esm/commands/sync/stat.d.ts +72 -72
  85. package/esm/commands/sync/stat.d.ts.map +1 -1
  86. package/esm/commands/sync/stat.js +116 -104
  87. package/esm/commands/sync/stat.js.map +1 -1
  88. package/esm/commands/sync/sync.d.ts +72 -60
  89. package/esm/commands/sync/sync.d.ts.map +1 -1
  90. package/esm/commands/sync/sync.js +127 -149
  91. package/esm/commands/sync/sync.js.map +1 -1
  92. package/esm/commands/tcpip.d.ts +5 -5
  93. package/esm/commands/tcpip.js +18 -18
  94. package/esm/crypto.d.ts +36 -36
  95. package/esm/crypto.js +248 -248
  96. package/esm/features.d.ts +10 -7
  97. package/esm/features.d.ts.map +1 -1
  98. package/esm/features.js +13 -10
  99. package/esm/features.js.map +1 -1
  100. package/esm/index.d.ts +9 -9
  101. package/esm/index.js +9 -9
  102. package/esm/packet.d.ts +45 -46
  103. package/esm/packet.d.ts.map +1 -1
  104. package/esm/packet.js +43 -48
  105. package/esm/packet.js.map +1 -1
  106. package/esm/socket/dispatcher.d.ts +59 -59
  107. package/esm/socket/dispatcher.d.ts.map +1 -1
  108. package/esm/socket/dispatcher.js +223 -234
  109. package/esm/socket/dispatcher.js.map +1 -1
  110. package/esm/socket/index.d.ts +2 -2
  111. package/esm/socket/index.js +2 -2
  112. package/esm/socket/socket.d.ts +59 -59
  113. package/esm/socket/socket.d.ts.map +1 -1
  114. package/esm/socket/socket.js +118 -118
  115. package/esm/socket/socket.js.map +1 -1
  116. package/esm/utils/auto-reset-event.d.ts +9 -9
  117. package/esm/utils/auto-reset-event.d.ts.map +1 -1
  118. package/esm/utils/auto-reset-event.js +33 -33
  119. package/esm/utils/auto-reset-event.js.map +1 -1
  120. package/esm/utils/base64.d.ts +27 -27
  121. package/esm/utils/base64.js +246 -246
  122. package/esm/utils/conditional-variable.d.ts +9 -0
  123. package/esm/utils/conditional-variable.d.ts.map +1 -0
  124. package/esm/utils/conditional-variable.js +34 -0
  125. package/esm/utils/conditional-variable.js.map +1 -0
  126. package/esm/utils/index.d.ts +4 -3
  127. package/esm/utils/index.d.ts.map +1 -1
  128. package/esm/utils/index.js +4 -3
  129. package/esm/utils/index.js.map +1 -1
  130. package/package.json +11 -10
  131. package/src/adb.ts +47 -37
  132. package/src/auth.ts +7 -6
  133. package/src/backend.ts +4 -4
  134. package/src/commands/base.ts +1 -1
  135. package/src/commands/framebuffer.ts +4 -4
  136. package/src/commands/index.ts +7 -8
  137. package/src/commands/reverse.ts +35 -10
  138. package/src/commands/subprocess/command.ts +12 -4
  139. package/src/commands/subprocess/index.ts +3 -3
  140. package/src/commands/subprocess/protocols/index.ts +3 -3
  141. package/src/commands/subprocess/protocols/none.ts +25 -11
  142. package/src/commands/subprocess/protocols/shell.ts +50 -28
  143. package/src/commands/subprocess/protocols/types.ts +8 -7
  144. package/src/commands/subprocess/utils.ts +1 -1
  145. package/src/commands/sync/index.ts +8 -7
  146. package/src/commands/sync/list.ts +42 -23
  147. package/src/commands/sync/pull.ts +40 -45
  148. package/src/commands/sync/push.ts +146 -39
  149. package/src/commands/sync/request.ts +20 -15
  150. package/src/commands/sync/response.ts +7 -6
  151. package/src/commands/sync/socket.ts +97 -0
  152. package/src/commands/sync/stat.ts +47 -42
  153. package/src/commands/sync/sync.ts +68 -108
  154. package/src/commands/tcpip.ts +5 -5
  155. package/src/features.ts +9 -6
  156. package/src/packet.ts +19 -34
  157. package/src/socket/dispatcher.ts +32 -47
  158. package/src/socket/index.ts +2 -2
  159. package/src/socket/socket.ts +26 -17
  160. package/src/utils/auto-reset-event.ts +14 -15
  161. package/src/utils/conditional-variable.ts +45 -0
  162. package/src/utils/index.ts +4 -3
  163. package/tsconfig.build.tsbuildinfo +1 -1
  164. package/src/commands/install.ts +0 -40
@@ -1,11 +1,8 @@
1
- import {
2
- type BufferedReadableStream,
3
- type WritableStreamDefaultWriter,
4
- } from "@yume-chan/stream-extra";
5
1
  import Struct, { placeholder } from "@yume-chan/struct";
6
2
 
7
3
  import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
8
4
  import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
5
+ import type { AdbSyncSocket } from "./socket.js";
9
6
 
10
7
  // https://github.com/python/cpython/blob/4e581d64b8aff3e2eda99b12f080c877bb78dfca/Lib/stat.py#L36
11
8
  export enum LinuxFileType {
@@ -47,7 +44,7 @@ export const AdbSyncLstatResponse = new Struct({ littleEndian: true })
47
44
  });
48
45
 
49
46
  export type AdbSyncLstatResponse =
50
- typeof AdbSyncLstatResponse["TDeserializeResult"];
47
+ (typeof AdbSyncLstatResponse)["TDeserializeResult"];
51
48
 
52
49
  export enum AdbSyncStatErrorCode {
53
50
  SUCCESS = 0,
@@ -101,52 +98,60 @@ export const AdbSyncStatResponse = new Struct({ littleEndian: true })
101
98
  });
102
99
 
103
100
  export type AdbSyncStatResponse =
104
- typeof AdbSyncStatResponse["TDeserializeResult"];
101
+ (typeof AdbSyncStatResponse)["TDeserializeResult"];
105
102
 
106
103
  export async function adbSyncLstat(
107
- stream: BufferedReadableStream,
108
- writer: WritableStreamDefaultWriter<Uint8Array>,
104
+ socket: AdbSyncSocket,
109
105
  path: string,
110
106
  v2: boolean
111
107
  ): Promise<AdbSyncStat> {
112
- if (v2) {
113
- await adbSyncWriteRequest(writer, AdbSyncRequestId.Lstat2, path);
114
- return await adbSyncReadResponse(
115
- stream,
116
- AdbSyncResponseId.Lstat2,
117
- AdbSyncStatResponse
118
- );
119
- } else {
120
- await adbSyncWriteRequest(writer, AdbSyncRequestId.Lstat, path);
121
- const response = await adbSyncReadResponse(
122
- stream,
123
- AdbSyncResponseId.Lstat,
124
- AdbSyncLstatResponse
125
- );
126
- return {
127
- mode: response.mode,
128
- // Convert to `BigInt` to make it compatible with `AdbSyncStatResponse`
129
- size: BigInt(response.size),
130
- mtime: BigInt(response.mtime),
131
- get type() {
132
- return response.type;
133
- },
134
- get permission() {
135
- return response.permission;
136
- },
137
- };
108
+ const locked = await socket.lock();
109
+ try {
110
+ if (v2) {
111
+ await adbSyncWriteRequest(locked, AdbSyncRequestId.LstatV2, path);
112
+ return await adbSyncReadResponse(
113
+ locked,
114
+ AdbSyncResponseId.Lstat2,
115
+ AdbSyncStatResponse
116
+ );
117
+ } else {
118
+ await adbSyncWriteRequest(locked, AdbSyncRequestId.Lstat, path);
119
+ const response = await adbSyncReadResponse(
120
+ locked,
121
+ AdbSyncResponseId.Lstat,
122
+ AdbSyncLstatResponse
123
+ );
124
+ return {
125
+ mode: response.mode,
126
+ // Convert to `BigInt` to make it compatible with `AdbSyncStatResponse`
127
+ size: BigInt(response.size),
128
+ mtime: BigInt(response.mtime),
129
+ get type() {
130
+ return response.type;
131
+ },
132
+ get permission() {
133
+ return response.permission;
134
+ },
135
+ };
136
+ }
137
+ } finally {
138
+ locked.release();
138
139
  }
139
140
  }
140
141
 
141
142
  export async function adbSyncStat(
142
- stream: BufferedReadableStream,
143
- writer: WritableStreamDefaultWriter<Uint8Array>,
143
+ socket: AdbSyncSocket,
144
144
  path: string
145
145
  ): Promise<AdbSyncStatResponse> {
146
- await adbSyncWriteRequest(writer, AdbSyncRequestId.Stat, path);
147
- return await adbSyncReadResponse(
148
- stream,
149
- AdbSyncResponseId.Stat,
150
- AdbSyncStatResponse
151
- );
146
+ const locked = await socket.lock();
147
+ try {
148
+ await adbSyncWriteRequest(locked, AdbSyncRequestId.Stat, path);
149
+ return await adbSyncReadResponse(
150
+ locked,
151
+ AdbSyncResponseId.Stat,
152
+ AdbSyncStatResponse
153
+ );
154
+ } finally {
155
+ locked.release();
156
+ }
152
157
  }
@@ -1,22 +1,16 @@
1
1
  import { AutoDisposable } from "@yume-chan/event";
2
- import {
3
- BufferedReadableStream,
4
- WrapReadableStream,
5
- WrapWritableStream,
6
- type ReadableStream,
7
- type WritableStream,
8
- type WritableStreamDefaultWriter,
9
- } from "@yume-chan/stream-extra";
10
-
11
- import { type Adb } from "../../adb.js";
12
- import { AdbFeatures } from "../../features.js";
13
- import { type AdbSocket } from "../../socket/index.js";
14
- import { AutoResetEvent } from "../../utils/index.js";
2
+ import type { Consumable, ReadableStream } from "@yume-chan/stream-extra";
3
+
4
+ import type { Adb } from "../../adb.js";
5
+ import { AdbFeature } from "../../features.js";
6
+ import type { AdbSocket } from "../../socket/index.js";
15
7
  import { escapeArg } from "../subprocess/index.js";
16
8
 
17
- import { adbSyncOpenDir, type AdbSyncEntry } from "./list.js";
9
+ import type { AdbSyncEntry } from "./list.js";
10
+ import { adbSyncOpenDir } from "./list.js";
18
11
  import { adbSyncPull } from "./pull.js";
19
12
  import { adbSyncPush } from "./push.js";
13
+ import { AdbSyncSocket } from "./socket.js";
20
14
  import { adbSyncLstat, adbSyncStat } from "./stat.js";
21
15
 
22
16
  /**
@@ -35,57 +29,64 @@ export function dirname(path: string): string {
35
29
  return path.substring(0, end);
36
30
  }
37
31
 
32
+ export interface AdbSyncWriteOptions {
33
+ filename: string;
34
+ file: ReadableStream<Consumable<Uint8Array>>;
35
+ mode?: number;
36
+ mtime?: number;
37
+ dryRun?: boolean;
38
+ }
39
+
38
40
  export class AdbSync extends AutoDisposable {
39
- protected adb: Adb;
41
+ protected _adb: Adb;
42
+ protected _socket: AdbSyncSocket;
40
43
 
41
- protected stream: BufferedReadableStream;
42
- // Getting another writer on a locked WritableStream will throw.
43
- // We don't want this behavior on higher-level APIs.
44
- // So we acquire the writer early and use a blocking lock to guard it.
45
- protected writer: WritableStreamDefaultWriter<Uint8Array>;
46
- protected sendLock = this.addDisposable(new AutoResetEvent());
44
+ private _supportsStat: boolean;
45
+ private _supportsListV2: boolean;
46
+ private _fixedPushMkdir: boolean;
47
+ private _supportsSendReceiveV2: boolean;
48
+ private _needPushMkdirWorkaround: boolean;
47
49
 
48
50
  public get supportsStat(): boolean {
49
- return this.adb.features.includes(AdbFeatures.StatV2);
51
+ return this._supportsStat;
50
52
  }
51
53
 
52
- public get supportsList2(): boolean {
53
- return this.adb.features.includes(AdbFeatures.ListV2);
54
+ public get supportsListV2(): boolean {
55
+ return this._supportsListV2;
54
56
  }
55
57
 
56
58
  public get fixedPushMkdir(): boolean {
57
- return this.adb.features.includes(AdbFeatures.FixedPushMkdir);
59
+ return this._fixedPushMkdir;
60
+ }
61
+
62
+ public get supportsSendReceiveV2(): boolean {
63
+ return this._supportsSendReceiveV2;
58
64
  }
59
65
 
60
66
  public get needPushMkdirWorkaround(): boolean {
61
- // https://android.googlesource.com/platform/packages/modules/adb/+/91768a57b7138166e0a3d11f79cd55909dda7014/client/file_sync_client.cpp#1361
62
- return (
63
- this.adb.features.includes(AdbFeatures.ShellV2) &&
64
- !this.fixedPushMkdir
65
- );
67
+ return this._needPushMkdirWorkaround;
66
68
  }
67
69
 
68
70
  public constructor(adb: Adb, socket: AdbSocket) {
69
71
  super();
70
72
 
71
- this.adb = adb;
72
- this.stream = new BufferedReadableStream(socket.readable);
73
- this.writer = socket.writable.getWriter();
73
+ this._adb = adb;
74
+ this._socket = new AdbSyncSocket(socket, adb.maxPayloadSize);
75
+
76
+ this._supportsStat = adb.supportsFeature(AdbFeature.StatV2);
77
+ this._supportsListV2 = adb.supportsFeature(AdbFeature.ListV2);
78
+ this._fixedPushMkdir = adb.supportsFeature(AdbFeature.FixedPushMkdir);
79
+ this._supportsSendReceiveV2 = adb.supportsFeature(
80
+ AdbFeature.SendReceiveV2
81
+ );
82
+ // https://android.googlesource.com/platform/packages/modules/adb/+/91768a57b7138166e0a3d11f79cd55909dda7014/client/file_sync_client.cpp#1361
83
+ this._needPushMkdirWorkaround =
84
+ this._adb.supportsFeature(AdbFeature.ShellV2) &&
85
+ !this.fixedPushMkdir;
74
86
  }
75
87
 
76
88
  public async lstat(path: string) {
77
- await this.sendLock.wait();
78
-
79
- try {
80
- return adbSyncLstat(
81
- this.stream,
82
- this.writer,
83
- path,
84
- this.supportsStat
85
- );
86
- } finally {
87
- this.sendLock.notify();
88
- }
89
+ return await adbSyncLstat(this._socket, path, this.supportsStat);
89
90
  }
90
91
 
91
92
  public async stat(path: string) {
@@ -93,13 +94,7 @@ export class AdbSync extends AutoDisposable {
93
94
  throw new Error("Not supported");
94
95
  }
95
96
 
96
- await this.sendLock.wait();
97
-
98
- try {
99
- return adbSyncStat(this.stream, this.writer, path);
100
- } finally {
101
- this.sendLock.notify();
102
- }
97
+ return await adbSyncStat(this._socket, path);
103
98
  }
104
99
 
105
100
  public async isDirectory(path: string): Promise<boolean> {
@@ -111,21 +106,8 @@ export class AdbSync extends AutoDisposable {
111
106
  }
112
107
  }
113
108
 
114
- public async *opendir(
115
- path: string
116
- ): AsyncGenerator<AdbSyncEntry, void, void> {
117
- await this.sendLock.wait();
118
-
119
- try {
120
- yield* adbSyncOpenDir(
121
- this.stream,
122
- this.writer,
123
- path,
124
- this.supportsList2
125
- );
126
- } finally {
127
- this.sendLock.notify();
128
- }
109
+ public opendir(path: string): AsyncGenerator<AdbSyncEntry, void, void> {
110
+ return adbSyncOpenDir(this._socket, path, this.supportsListV2);
129
111
  }
130
112
 
131
113
  public async readdir(path: string) {
@@ -143,61 +125,39 @@ export class AdbSync extends AutoDisposable {
143
125
  * @returns A `ReadableStream` that reads from the file.
144
126
  */
145
127
  public read(filename: string): ReadableStream<Uint8Array> {
146
- return new WrapReadableStream({
147
- start: async () => {
148
- await this.sendLock.wait();
149
- return adbSyncPull(this.stream, this.writer, filename);
150
- },
151
- close: () => {
152
- this.sendLock.notify();
153
- },
154
- });
128
+ return adbSyncPull(this._socket, filename);
155
129
  }
156
130
 
157
131
  /**
158
132
  * Write (or overwrite) a file on device.
159
133
  *
160
134
  * @param filename The full path of the file on device to write.
135
+ * @param file The content to write.
161
136
  * @param mode The unix permissions of the file.
162
137
  * @param mtime The modified time of the file.
163
138
  * @returns A `WritableStream` that writes to the file.
164
139
  */
165
- public write(
166
- filename: string,
167
- mode?: number,
168
- mtime?: number
169
- ): WritableStream<Uint8Array> {
170
- return new WrapWritableStream({
171
- start: async () => {
172
- await this.sendLock.wait();
173
-
174
- if (this.needPushMkdirWorkaround) {
175
- // It may fail if the path is already existed.
176
- // Ignore the result.
177
- // TODO: sync: test push mkdir workaround (need an Android 8 device)
178
- await this.adb.subprocess.spawnAndWait([
179
- "mkdir",
180
- "-p",
181
- escapeArg(dirname(filename)),
182
- ]);
183
- }
184
-
185
- return adbSyncPush(
186
- this.stream,
187
- this.writer,
188
- filename,
189
- mode,
190
- mtime
191
- );
192
- },
193
- close: () => {
194
- this.sendLock.notify();
195
- },
140
+ public async write(options: AdbSyncWriteOptions) {
141
+ if (this.needPushMkdirWorkaround) {
142
+ // It may fail if the path is already existed.
143
+ // Ignore the result.
144
+ // TODO: sync: test push mkdir workaround (need an Android 8 device)
145
+ await this._adb.subprocess.spawnAndWait([
146
+ "mkdir",
147
+ "-p",
148
+ escapeArg(dirname(options.filename)),
149
+ ]);
150
+ }
151
+
152
+ await adbSyncPush({
153
+ v2: this.supportsSendReceiveV2,
154
+ socket: this._socket,
155
+ ...options,
196
156
  });
197
157
  }
198
158
 
199
159
  public override async dispose() {
200
160
  super.dispose();
201
- await this.writer.close();
161
+ await this._socket.close();
202
162
  }
203
163
  }
@@ -1,4 +1,4 @@
1
- import { AdbCommandBase } from './base.js';
1
+ import { AdbCommandBase } from "./base.js";
2
2
 
3
3
  export class AdbTcpIpCommand extends AdbCommandBase {
4
4
  public async setPort(port: number): Promise<void> {
@@ -8,14 +8,14 @@ export class AdbTcpIpCommand extends AdbCommandBase {
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('Invalid response');
11
+ throw new Error("Invalid response");
12
12
  }
13
13
  }
14
14
 
15
15
  public async disable(): Promise<void> {
16
- const output = await this.adb.createSocketAndWait('usb:');
17
- if (output !== 'restarting in USB mode\n') {
18
- throw new Error('Invalid response');
16
+ const output = await this.adb.createSocketAndWait("usb:");
17
+ if (output !== "restarting in USB mode\n") {
18
+ throw new Error("Invalid response");
19
19
  }
20
20
  }
21
21
  }
package/src/features.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  // The order follows
2
2
  // https://android.googlesource.com/platform/packages/modules/adb/+/79010dc6d5ca7490c493df800d4421730f5466ca/transport.cpp#1252
3
- export enum AdbFeatures {
4
- ShellV2 = 'shell_v2',
5
- Cmd = 'cmd',
6
- StatV2 = 'stat_v2',
7
- ListV2 = 'ls_v2',
8
- FixedPushMkdir = 'fixed_push_mkdir',
3
+ export enum AdbFeature {
4
+ ShellV2 = "shell_v2",
5
+ Cmd = "cmd",
6
+ StatV2 = "stat_v2",
7
+ ListV2 = "ls_v2",
8
+ FixedPushMkdir = "fixed_push_mkdir",
9
+ Abb = "abb",
10
+ AbbExec = "abb_exec",
11
+ SendReceiveV2 = "sendrecv_v2",
9
12
  }
package/src/packet.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { TransformStream } from "@yume-chan/stream-extra";
1
+ import { ConsumableTransformStream } from "@yume-chan/stream-extra";
2
2
  import Struct from "@yume-chan/struct";
3
3
 
4
4
  export enum AdbCommand {
@@ -18,15 +18,15 @@ export const AdbPacketHeader = new Struct({ littleEndian: true })
18
18
  .uint32("checksum")
19
19
  .int32("magic");
20
20
 
21
- export type AdbPacketHeader = typeof AdbPacketHeader["TDeserializeResult"];
21
+ export type AdbPacketHeader = (typeof AdbPacketHeader)["TDeserializeResult"];
22
22
 
23
- type AdbPacketHeaderInit = typeof AdbPacketHeader["TInit"];
23
+ type AdbPacketHeaderInit = (typeof AdbPacketHeader)["TInit"];
24
24
 
25
25
  export const AdbPacket = new Struct({ littleEndian: true })
26
26
  .fields(AdbPacketHeader)
27
27
  .uint8Array("payload", { lengthField: "payloadLength" });
28
28
 
29
- export type AdbPacket = typeof AdbPacket["TDeserializeResult"];
29
+ export type AdbPacket = (typeof AdbPacket)["TDeserializeResult"];
30
30
 
31
31
  /**
32
32
  * `AdbPacketData` contains all the useful fields of `AdbPacket`.
@@ -39,50 +39,35 @@ export type AdbPacket = typeof AdbPacket["TDeserializeResult"];
39
39
  * so `AdbSocket#writable#write` only needs `AdbPacketData`.
40
40
  */
41
41
  export type AdbPacketData = Omit<
42
- typeof AdbPacket["TInit"],
42
+ (typeof AdbPacket)["TInit"],
43
43
  "checksum" | "magic"
44
44
  >;
45
45
 
46
- // All fields except `magic`, which can be calculated in `AdbPacketSerializeStream`
47
- export type AdbPacketInit = Omit<typeof AdbPacket["TInit"], "magic">;
46
+ export type AdbPacketInit = (typeof AdbPacket)["TInit"];
48
47
 
49
- export function calculateChecksum(payload: Uint8Array): number;
50
- export function calculateChecksum(init: AdbPacketData): AdbPacketInit;
51
- export function calculateChecksum(
52
- payload: Uint8Array | AdbPacketData
53
- ): number | AdbPacketInit {
54
- if (payload instanceof Uint8Array) {
55
- return payload.reduce((result, item) => result + item, 0);
56
- } else {
57
- (payload as AdbPacketInit).checksum = calculateChecksum(
58
- payload.payload
59
- );
60
- return payload as AdbPacketInit;
61
- }
48
+ export function calculateChecksum(payload: Uint8Array): number {
49
+ return payload.reduce((result, item) => result + item, 0);
62
50
  }
63
51
 
64
- export class AdbPacketSerializeStream extends TransformStream<
52
+ export class AdbPacketSerializeStream extends ConsumableTransformStream<
65
53
  AdbPacketInit,
66
54
  Uint8Array
67
55
  > {
68
56
  public constructor() {
57
+ const headerBuffer = new Uint8Array(AdbPacketHeader.size);
69
58
  super({
70
- transform: (init, controller) => {
71
- // This syntax is ugly, but I don't want to create a new object.
72
- (init as unknown as AdbPacketHeaderInit).magic =
73
- init.command ^ 0xffffffff;
74
- (init as unknown as AdbPacketHeaderInit).payloadLength =
75
- init.payload.byteLength;
59
+ transform: async (chunk, controller) => {
60
+ const init = chunk as AdbPacketInit & AdbPacketHeaderInit;
61
+ init.payloadLength = init.payload.byteLength;
76
62
 
77
- controller.enqueue(
78
- AdbPacketHeader.serialize(
79
- init as unknown as AdbPacketHeaderInit
80
- )
81
- );
63
+ AdbPacketHeader.serialize(init, headerBuffer);
64
+ await controller.enqueue(headerBuffer);
82
65
 
83
66
  if (init.payload.byteLength) {
84
- // Enqueue payload separately to avoid copying
85
- controller.enqueue(init.payload);
67
+ // USB protocol preserves packet boundaries,
68
+ // so we must write payload separately as native ADB does,
69
+ // otherwise the read operation on device will fail.
70
+ await controller.enqueue(init.payload);
86
71
  }
87
72
  },
88
73
  });
@@ -1,22 +1,24 @@
1
1
  import { AsyncOperationManager, PromiseResolver } from "@yume-chan/async";
2
- import { type RemoveEventListener } from "@yume-chan/event";
2
+ import type { RemoveEventListener } from "@yume-chan/event";
3
+ import type {
4
+ Consumable,
5
+ ReadableWritablePair,
6
+ WritableStreamDefaultWriter,
7
+ } from "@yume-chan/stream-extra";
3
8
  import {
4
9
  AbortController,
10
+ ConsumableWritableStream,
5
11
  WritableStream,
6
- type ReadableWritablePair,
7
- type WritableStreamDefaultWriter,
8
12
  } from "@yume-chan/stream-extra";
9
- import { EMPTY_UINT8_ARRAY, type ValueOrPromise } from "@yume-chan/struct";
13
+ import type { ValueOrPromise } from "@yume-chan/struct";
14
+ import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct";
10
15
 
11
- import {
12
- AdbCommand,
13
- calculateChecksum,
14
- type AdbPacketData,
15
- type AdbPacketInit,
16
- } from "../packet.js";
16
+ import type { AdbPacketData, AdbPacketInit } from "../packet.js";
17
+ import { AdbCommand, calculateChecksum } from "../packet.js";
17
18
  import { decodeUtf8, encodeUtf8 } from "../utils/index.js";
18
19
 
19
- import { AdbSocketController, type AdbSocket } from "./socket.js";
20
+ import type { AdbSocket } from "./socket.js";
21
+ import { AdbSocketController } from "./socket.js";
20
22
 
21
23
  export interface AdbPacketDispatcherOptions {
22
24
  calculateChecksum: boolean;
@@ -57,7 +59,7 @@ export class AdbPacketDispatcher implements Closeable {
57
59
  */
58
60
  private readonly sockets = new Map<number, AdbSocketController>();
59
61
 
60
- private _writer!: WritableStreamDefaultWriter<AdbPacketInit>;
62
+ private _writer: WritableStreamDefaultWriter<Consumable<AdbPacketInit>>;
61
63
 
62
64
  public readonly options: AdbPacketDispatcherOptions;
63
65
 
@@ -72,7 +74,10 @@ export class AdbPacketDispatcher implements Closeable {
72
74
  private _abortController = new AbortController();
73
75
 
74
76
  public constructor(
75
- connection: ReadableWritablePair<AdbPacketData, AdbPacketInit>,
77
+ connection: ReadableWritablePair<
78
+ AdbPacketData,
79
+ Consumable<AdbPacketInit>
80
+ >,
76
81
  options: AdbPacketDispatcherOptions
77
82
  ) {
78
83
  this.options = options;
@@ -273,50 +278,30 @@ export class AdbPacketDispatcher implements Closeable {
273
278
  return controller.socket;
274
279
  }
275
280
 
276
- public sendPacket(packet: AdbPacketInit): Promise<void>;
277
- public sendPacket(
281
+ public async sendPacket(
278
282
  command: AdbCommand,
279
283
  arg0: number,
280
284
  arg1: number,
281
- payload?: string | Uint8Array
282
- ): Promise<void>;
283
- public async sendPacket(
284
- packetOrCommand: AdbPacketInit | AdbCommand,
285
- arg0?: number,
286
- arg1?: number,
287
285
  payload: string | Uint8Array = EMPTY_UINT8_ARRAY
288
286
  ): Promise<void> {
289
- let init: AdbPacketData;
290
- if (arg0 === undefined) {
291
- init = packetOrCommand as AdbPacketInit;
292
- } else {
293
- if (typeof payload === "string") {
294
- payload = encodeUtf8(payload);
295
- }
296
-
297
- init = {
298
- command: packetOrCommand as AdbCommand,
299
- arg0: arg0,
300
- arg1: arg1 as number,
301
- payload,
302
- };
287
+ if (typeof payload === "string") {
288
+ payload = encodeUtf8(payload);
303
289
  }
304
290
 
305
- if (
306
- init.payload &&
307
- init.payload.byteLength > this.options.maxPayloadSize
308
- ) {
291
+ if (payload.byteLength > this.options.maxPayloadSize) {
309
292
  throw new Error("payload too large");
310
293
  }
311
294
 
312
- if (this.options.calculateChecksum) {
313
- calculateChecksum(init);
314
- } else {
315
- (init as AdbPacketInit).checksum = 0;
316
- }
317
-
318
- await this._writer.ready;
319
- await this._writer.write(init as AdbPacketInit);
295
+ await ConsumableWritableStream.write(this._writer, {
296
+ command,
297
+ arg0,
298
+ arg1,
299
+ payload,
300
+ checksum: this.options.calculateChecksum
301
+ ? calculateChecksum(payload)
302
+ : 0,
303
+ magic: command ^ 0xffffffff,
304
+ });
320
305
  }
321
306
 
322
307
  public async close() {
@@ -1,2 +1,2 @@
1
- export * from './dispatcher.js';
2
- export * from './socket.js';
1
+ export * from "./dispatcher.js";
2
+ export * from "./socket.js";