@yume-chan/adb 0.0.17 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/CHANGELOG.json +27 -0
  2. package/CHANGELOG.md +16 -1
  3. package/LICENSE +1 -1
  4. package/esm/adb.d.ts +63 -60
  5. package/esm/adb.d.ts.map +1 -1
  6. package/esm/adb.js +257 -229
  7. package/esm/adb.js.map +1 -1
  8. package/esm/auth.d.ts +51 -51
  9. package/esm/auth.d.ts.map +1 -1
  10. package/esm/auth.js +95 -96
  11. package/esm/auth.js.map +1 -1
  12. package/esm/backend.d.ts +8 -8
  13. package/esm/backend.d.ts.map +1 -1
  14. package/esm/backend.js +1 -1
  15. package/esm/commands/base.d.ts +6 -6
  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 -47
  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 +27 -21
  28. package/esm/commands/install.js.map +1 -1
  29. package/esm/commands/power.d.ts +22 -22
  30. package/esm/commands/power.d.ts.map +1 -1
  31. package/esm/commands/power.js +48 -44
  32. package/esm/commands/power.js.map +1 -1
  33. package/esm/commands/reverse.d.ts +41 -28
  34. package/esm/commands/reverse.d.ts.map +1 -1
  35. package/esm/commands/reverse.js +125 -98
  36. package/esm/commands/reverse.js.map +1 -1
  37. package/esm/commands/subprocess/command.d.ts +57 -51
  38. package/esm/commands/subprocess/command.d.ts.map +1 -1
  39. package/esm/commands/subprocess/command.js +86 -82
  40. package/esm/commands/subprocess/command.js.map +1 -1
  41. package/esm/commands/subprocess/index.d.ts +3 -3
  42. package/esm/commands/subprocess/index.js +3 -3
  43. package/esm/commands/subprocess/protocols/index.d.ts +3 -3
  44. package/esm/commands/subprocess/protocols/index.js +3 -3
  45. package/esm/commands/subprocess/protocols/none.d.ts +35 -35
  46. package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
  47. package/esm/commands/subprocess/protocols/none.js +65 -55
  48. package/esm/commands/subprocess/protocols/none.js.map +1 -1
  49. package/esm/commands/subprocess/protocols/shell.d.ts +39 -38
  50. package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
  51. package/esm/commands/subprocess/protocols/shell.js +166 -154
  52. package/esm/commands/subprocess/protocols/shell.js.map +1 -1
  53. package/esm/commands/subprocess/protocols/types.d.ts +49 -49
  54. package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
  55. package/esm/commands/subprocess/protocols/types.js +1 -1
  56. package/esm/commands/subprocess/utils.d.ts +1 -1
  57. package/esm/commands/subprocess/utils.js +18 -18
  58. package/esm/commands/sync/index.d.ts +8 -7
  59. package/esm/commands/sync/index.d.ts.map +1 -1
  60. package/esm/commands/sync/index.js +8 -7
  61. package/esm/commands/sync/index.js.map +1 -1
  62. package/esm/commands/sync/list.d.ts +42 -40
  63. package/esm/commands/sync/list.d.ts.map +1 -1
  64. package/esm/commands/sync/list.js +67 -35
  65. package/esm/commands/sync/list.js.map +1 -1
  66. package/esm/commands/sync/pull.d.ts +13 -11
  67. package/esm/commands/sync/pull.d.ts.map +1 -1
  68. package/esm/commands/sync/pull.js +35 -36
  69. package/esm/commands/sync/pull.js.map +1 -1
  70. package/esm/commands/sync/push.d.ts +46 -7
  71. package/esm/commands/sync/push.d.ts.map +1 -1
  72. package/esm/commands/sync/push.js +89 -23
  73. package/esm/commands/sync/push.js.map +1 -1
  74. package/esm/commands/sync/request.d.ts +26 -23
  75. package/esm/commands/sync/request.d.ts.map +1 -1
  76. package/esm/commands/sync/request.js +40 -42
  77. package/esm/commands/sync/request.js.map +1 -1
  78. package/esm/commands/sync/response.d.ts +19 -19
  79. package/esm/commands/sync/response.d.ts.map +1 -1
  80. package/esm/commands/sync/response.js +54 -54
  81. package/esm/commands/sync/response.js.map +1 -1
  82. package/esm/commands/sync/socket.d.ts +27 -0
  83. package/esm/commands/sync/socket.d.ts.map +1 -0
  84. package/esm/commands/sync/socket.js +66 -0
  85. package/esm/commands/sync/socket.js.map +1 -0
  86. package/esm/commands/sync/stat.d.ts +72 -72
  87. package/esm/commands/sync/stat.d.ts.map +1 -1
  88. package/esm/commands/sync/stat.js +116 -94
  89. package/esm/commands/sync/stat.js.map +1 -1
  90. package/esm/commands/sync/sync.d.ts +72 -60
  91. package/esm/commands/sync/sync.d.ts.map +1 -1
  92. package/esm/commands/sync/sync.js +127 -148
  93. package/esm/commands/sync/sync.js.map +1 -1
  94. package/esm/commands/tcpip.d.ts +5 -5
  95. package/esm/commands/tcpip.js +18 -18
  96. package/esm/crypto.d.ts +36 -36
  97. package/esm/crypto.d.ts.map +1 -1
  98. package/esm/crypto.js +248 -238
  99. package/esm/crypto.js.map +1 -1
  100. package/esm/features.d.ts +10 -7
  101. package/esm/features.d.ts.map +1 -1
  102. package/esm/features.js +13 -10
  103. package/esm/features.js.map +1 -1
  104. package/esm/index.d.ts +9 -9
  105. package/esm/index.d.ts.map +1 -1
  106. package/esm/index.js +9 -9
  107. package/esm/index.js.map +1 -1
  108. package/esm/packet.d.ts +45 -46
  109. package/esm/packet.d.ts.map +1 -1
  110. package/esm/packet.js +43 -46
  111. package/esm/packet.js.map +1 -1
  112. package/esm/socket/dispatcher.d.ts +59 -59
  113. package/esm/socket/dispatcher.d.ts.map +1 -1
  114. package/esm/socket/dispatcher.js +223 -231
  115. package/esm/socket/dispatcher.js.map +1 -1
  116. package/esm/socket/index.d.ts +2 -2
  117. package/esm/socket/index.js +2 -2
  118. package/esm/socket/socket.d.ts +59 -59
  119. package/esm/socket/socket.d.ts.map +1 -1
  120. package/esm/socket/socket.js +118 -98
  121. package/esm/socket/socket.js.map +1 -1
  122. package/esm/utils/auto-reset-event.d.ts +9 -9
  123. package/esm/utils/auto-reset-event.d.ts.map +1 -1
  124. package/esm/utils/auto-reset-event.js +33 -33
  125. package/esm/utils/auto-reset-event.js.map +1 -1
  126. package/esm/utils/base64.d.ts +27 -27
  127. package/esm/utils/base64.d.ts.map +1 -1
  128. package/esm/utils/base64.js +246 -245
  129. package/esm/utils/base64.js.map +1 -1
  130. package/esm/utils/conditional-variable.d.ts +9 -0
  131. package/esm/utils/conditional-variable.d.ts.map +1 -0
  132. package/esm/utils/conditional-variable.js +34 -0
  133. package/esm/utils/conditional-variable.js.map +1 -0
  134. package/esm/utils/index.d.ts +4 -3
  135. package/esm/utils/index.d.ts.map +1 -1
  136. package/esm/utils/index.js +4 -3
  137. package/esm/utils/index.js.map +1 -1
  138. package/package.json +17 -13
  139. package/src/adb.ts +160 -101
  140. package/src/auth.ts +31 -22
  141. package/src/backend.ts +6 -4
  142. package/src/commands/base.ts +2 -2
  143. package/src/commands/framebuffer.ts +37 -41
  144. package/src/commands/index.ts +7 -8
  145. package/src/commands/power.ts +15 -11
  146. package/src/commands/reverse.ts +74 -30
  147. package/src/commands/subprocess/command.ts +34 -23
  148. package/src/commands/subprocess/index.ts +3 -3
  149. package/src/commands/subprocess/protocols/index.ts +3 -3
  150. package/src/commands/subprocess/protocols/none.ts +26 -11
  151. package/src/commands/subprocess/protocols/shell.ts +110 -56
  152. package/src/commands/subprocess/protocols/types.ts +10 -6
  153. package/src/commands/subprocess/utils.ts +1 -1
  154. package/src/commands/sync/index.ts +8 -7
  155. package/src/commands/sync/list.ts +74 -28
  156. package/src/commands/sync/pull.ts +49 -37
  157. package/src/commands/sync/push.ts +153 -32
  158. package/src/commands/sync/request.ts +37 -34
  159. package/src/commands/sync/response.ts +34 -27
  160. package/src/commands/sync/socket.ts +97 -0
  161. package/src/commands/sync/stat.ts +98 -70
  162. package/src/commands/sync/sync.ts +78 -97
  163. package/src/commands/tcpip.ts +5 -5
  164. package/src/crypto.ts +60 -32
  165. package/src/features.ts +9 -6
  166. package/src/index.ts +9 -10
  167. package/src/packet.ts +41 -46
  168. package/src/socket/dispatcher.ts +130 -108
  169. package/src/socket/index.ts +2 -2
  170. package/src/socket/socket.ts +84 -34
  171. package/src/utils/auto-reset-event.ts +16 -17
  172. package/src/utils/base64.ts +51 -41
  173. package/src/utils/conditional-variable.ts +45 -0
  174. package/src/utils/index.ts +4 -3
  175. package/tsconfig.build.json +1 -1
  176. package/tsconfig.build.tsbuildinfo +1 -1
  177. package/src/commands/install.ts +0 -32
@@ -1,12 +1,28 @@
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';
1
+ import { PromiseResolver } from "@yume-chan/async";
2
+ import type {
3
+ Consumable,
4
+ PushReadableStreamController,
5
+ ReadableStream,
6
+ WritableStreamDefaultWriter,
7
+ } from "@yume-chan/stream-extra";
8
+ import {
9
+ ConsumableTransformStream,
10
+ ConsumableWritableStream,
11
+ PushReadableStream,
12
+ StructDeserializeStream,
13
+ TransformStream,
14
+ WritableStream,
15
+ pipeFrom,
16
+ } from "@yume-chan/stream-extra";
17
+ import type { StructValueType } from "@yume-chan/struct";
18
+ import Struct, { placeholder } from "@yume-chan/struct";
19
+
20
+ import type { Adb } from "../../../adb.js";
21
+ import { AdbFeature } from "../../../features.js";
22
+ import type { AdbSocket } from "../../../socket/index.js";
23
+ import { encodeUtf8 } from "../../../utils/index.js";
24
+
25
+ import type { AdbSubprocessProtocol } from "./types.js";
10
26
 
11
27
  export enum AdbShellProtocolId {
12
28
  Stdin,
@@ -18,33 +34,38 @@ export enum AdbShellProtocolId {
18
34
  }
19
35
 
20
36
  // This packet format is used in both direction.
21
- const AdbShellProtocolPacket =
22
- new Struct({ littleEndian: true })
23
- .uint8('id', placeholder<AdbShellProtocolId>())
24
- .uint32('length')
25
- .uint8Array('data', { lengthField: 'length' });
37
+ const AdbShellProtocolPacket = new Struct({ littleEndian: true })
38
+ .uint8("id", placeholder<AdbShellProtocolId>())
39
+ .uint32("length")
40
+ .uint8Array("data", { lengthField: "length" });
26
41
 
27
- type AdbShellProtocolPacketInit = typeof AdbShellProtocolPacket['TInit'];
42
+ type AdbShellProtocolPacketInit = (typeof AdbShellProtocolPacket)["TInit"];
28
43
 
29
44
  type AdbShellProtocolPacket = StructValueType<typeof AdbShellProtocolPacket>;
30
45
 
31
- class StdinSerializeStream extends TransformStream<Uint8Array, AdbShellProtocolPacketInit>{
46
+ class StdinSerializeStream extends ConsumableTransformStream<
47
+ Uint8Array,
48
+ AdbShellProtocolPacketInit
49
+ > {
32
50
  constructor() {
33
51
  super({
34
- transform(chunk, controller) {
35
- controller.enqueue({
52
+ async transform(chunk, controller) {
53
+ await controller.enqueue({
36
54
  id: AdbShellProtocolId.Stdin,
37
55
  data: chunk,
38
56
  });
39
57
  },
40
58
  flush() {
41
59
  // TODO: AdbShellSubprocessProtocol: support closing stdin
42
- }
60
+ },
43
61
  });
44
62
  }
45
63
  }
46
64
 
47
- class StdoutDeserializeStream extends TransformStream<AdbShellProtocolPacket, Uint8Array>{
65
+ class StdoutDeserializeStream extends TransformStream<
66
+ AdbShellProtocolPacket,
67
+ Uint8Array
68
+ > {
48
69
  constructor(type: AdbShellProtocolId.Stdout | AdbShellProtocolId.Stderr) {
49
70
  super({
50
71
  transform(chunk, controller) {
@@ -56,15 +77,17 @@ class StdoutDeserializeStream extends TransformStream<AdbShellProtocolPacket, Ui
56
77
  }
57
78
  }
58
79
 
59
- class MultiplexStream<T>{
80
+ class MultiplexStream<T> {
60
81
  private _readable: PushReadableStream<T>;
61
82
  private _readableController!: PushReadableStreamController<T>;
62
- public get readable() { return this._readable; }
83
+ public get readable() {
84
+ return this._readable;
85
+ }
63
86
 
64
87
  private _activeCount = 0;
65
88
 
66
89
  constructor() {
67
- this._readable = new PushReadableStream(controller => {
90
+ this._readable = new PushReadableStream((controller) => {
68
91
  this._readableController = controller;
69
92
  });
70
93
  }
@@ -77,13 +100,13 @@ class MultiplexStream<T>{
77
100
  write: async (chunk) => {
78
101
  await this._readableController.enqueue(chunk);
79
102
  },
80
- abort: async (e) => {
103
+ abort: () => {
81
104
  this._activeCount -= 1;
82
105
  if (this._activeCount === 0) {
83
106
  this._readableController.close();
84
107
  }
85
108
  },
86
- close: async () => {
109
+ close: () => {
87
110
  this._activeCount -= 1;
88
111
  if (this._activeCount === 0) {
89
112
  this._readableController.close();
@@ -103,32 +126,46 @@ class MultiplexStream<T>{
103
126
  */
104
127
  export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
105
128
  public static isSupported(adb: Adb) {
106
- return adb.features.includes(AdbFeatures.ShellV2);
129
+ return adb.supportsFeature(AdbFeature.ShellV2);
107
130
  }
108
131
 
109
132
  public static async pty(adb: Adb, command: string) {
110
133
  // TODO: AdbShellSubprocessProtocol: Support setting `XTERM` environment variable
111
- return new AdbSubprocessShellProtocol(await adb.createSocket(`shell,v2,pty:${command}`));
134
+ return new AdbSubprocessShellProtocol(
135
+ await adb.createSocket(`shell,v2,pty:${command}`)
136
+ );
112
137
  }
113
138
 
114
139
  public static async raw(adb: Adb, command: string) {
115
- return new AdbSubprocessShellProtocol(await adb.createSocket(`shell,v2,raw:${command}`));
140
+ return new AdbSubprocessShellProtocol(
141
+ await adb.createSocket(`shell,v2,raw:${command}`)
142
+ );
116
143
  }
117
144
 
118
145
  private readonly _socket: AdbSocket;
119
- private _socketWriter: WritableStreamDefaultWriter<AdbShellProtocolPacketInit>;
146
+ private _socketWriter: WritableStreamDefaultWriter<
147
+ Consumable<AdbShellProtocolPacketInit>
148
+ >;
120
149
 
121
- private _stdin: WritableStream<Uint8Array>;
122
- public get stdin() { return this._stdin; }
150
+ private _stdin: WritableStream<Consumable<Uint8Array>>;
151
+ public get stdin() {
152
+ return this._stdin;
153
+ }
123
154
 
124
155
  private _stdout: ReadableStream<Uint8Array>;
125
- public get stdout() { return this._stdout; }
156
+ public get stdout() {
157
+ return this._stdout;
158
+ }
126
159
 
127
160
  private _stderr: ReadableStream<Uint8Array>;
128
- public get stderr() { return this._stderr; }
161
+ public get stderr() {
162
+ return this._stderr;
163
+ }
129
164
 
130
165
  private readonly _exit = new PromiseResolver<number>();
131
- public get exit() { return this._exit.promise; }
166
+ public get exit() {
167
+ return this._exit.promise;
168
+ }
132
169
 
133
170
  public constructor(socket: AdbSocket) {
134
171
  this._socket = socket;
@@ -141,28 +178,45 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
141
178
 
142
179
  const [stdout, stderr] = socket.readable
143
180
  .pipeThrough(new StructDeserializeStream(AdbShellProtocolPacket))
144
- .pipeThrough(new TransformStream<AdbShellProtocolPacket, AdbShellProtocolPacket>({
145
- transform: (chunk, controller) => {
146
- if (chunk.id === AdbShellProtocolId.Exit) {
147
- this._exit.resolve(new Uint8Array(chunk.data)[0]!);
148
- // We can let `StdoutDeserializeStream` to process `AdbShellProtocolId.Exit`,
149
- // but since we need this `TransformStream` to capture the exit code anyway,
150
- // terminating child streams here is killing two birds with one stone.
151
- controller.terminate();
152
- return;
153
- }
154
- controller.enqueue(chunk);
155
- }
156
- }))
181
+ .pipeThrough(
182
+ new TransformStream<
183
+ AdbShellProtocolPacket,
184
+ AdbShellProtocolPacket
185
+ >({
186
+ transform: (chunk, controller) => {
187
+ if (chunk.id === AdbShellProtocolId.Exit) {
188
+ this._exit.resolve(new Uint8Array(chunk.data)[0]!);
189
+ // We can let `StdoutDeserializeStream` to process `AdbShellProtocolId.Exit`,
190
+ // but since we need this `TransformStream` to capture the exit code anyway,
191
+ // terminating child streams here is killing two birds with one stone.
192
+ controller.terminate();
193
+ return;
194
+ }
195
+ controller.enqueue(chunk);
196
+ },
197
+ })
198
+ )
157
199
  .tee();
158
- this._stdout = stdout
159
- .pipeThrough(new StdoutDeserializeStream(AdbShellProtocolId.Stdout));
160
- this._stderr = stderr
161
- .pipeThrough(new StdoutDeserializeStream(AdbShellProtocolId.Stderr));
162
-
163
- const multiplexer = new MultiplexStream<AdbShellProtocolPacketInit>();
164
- multiplexer.readable
165
- .pipeThrough(new StructSerializeStream(AdbShellProtocolPacket))
200
+ this._stdout = stdout.pipeThrough(
201
+ new StdoutDeserializeStream(AdbShellProtocolId.Stdout)
202
+ );
203
+ this._stderr = stderr.pipeThrough(
204
+ new StdoutDeserializeStream(AdbShellProtocolId.Stderr)
205
+ );
206
+
207
+ const multiplexer = new MultiplexStream<
208
+ Consumable<AdbShellProtocolPacketInit>
209
+ >();
210
+ void multiplexer.readable
211
+ .pipeThrough(
212
+ new ConsumableTransformStream({
213
+ async transform(chunk, controller) {
214
+ await controller.enqueue(
215
+ AdbShellProtocolPacket.serialize(chunk)
216
+ );
217
+ },
218
+ })
219
+ )
166
220
  .pipeTo(socket.writable);
167
221
 
168
222
  this._stdin = pipeFrom(
@@ -174,7 +228,7 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
174
228
  }
175
229
 
176
230
  public async resize(rows: number, cols: number) {
177
- await this._socketWriter.write({
231
+ await ConsumableWritableStream.write(this._socketWriter, {
178
232
  id: AdbShellProtocolId.WindowSizeChange,
179
233
  data: encodeUtf8(
180
234
  // The "correct" format is `${rows}x${cols},${x_pixels}x${y_pixels}`
@@ -1,14 +1,18 @@
1
- import type { ReadableStream, WritableStream } from '@yume-chan/stream-extra';
2
- import type { ValueOrPromise } from '@yume-chan/struct';
1
+ import type {
2
+ Consumable,
3
+ ReadableStream,
4
+ WritableStream,
5
+ } from "@yume-chan/stream-extra";
6
+ import type { ValueOrPromise } from "@yume-chan/struct";
3
7
 
4
- import type { Adb } from '../../../adb.js';
5
- import type { AdbSocket } from '../../../socket/index.js';
8
+ import type { Adb } from "../../../adb.js";
9
+ import type { AdbSocket } from "../../../socket/index.js";
6
10
 
7
11
  export interface AdbSubprocessProtocol {
8
12
  /**
9
13
  * A WritableStream that writes to the `stdin` stream.
10
14
  */
11
- readonly stdin: WritableStream<Uint8Array>;
15
+ readonly stdin: WritableStream<Consumable<Uint8Array>>;
12
16
 
13
17
  /**
14
18
  * The `stdout` stream of the process.
@@ -56,5 +60,5 @@ export interface AdbSubprocessProtocolConstructor {
56
60
  raw(adb: Adb, command: string): ValueOrPromise<AdbSubprocessProtocol>;
57
61
 
58
62
  /** Creates a new `AdbShell` by attaching to an exist `AdbSocket` */
59
- new(socket: AdbSocket): AdbSubprocessProtocol;
63
+ new (socket: AdbSocket): AdbSubprocessProtocol;
60
64
  }
@@ -1,5 +1,5 @@
1
1
  export function escapeArg(s: string) {
2
- let result = '';
2
+ let result = "";
3
3
  result += `'`;
4
4
 
5
5
  let base = 0;
@@ -1,7 +1,8 @@
1
- export * from './list.js';
2
- export * from './pull.js';
3
- export * from './push.js';
4
- export * from './request.js';
5
- export * from './response.js';
6
- export * from './stat.js';
7
- export * from './sync.js';
1
+ export * from "./list.js";
2
+ export * from "./pull.js";
3
+ export * from "./push.js";
4
+ export * from "./request.js";
5
+ export * from "./response.js";
6
+ export * from "./socket.js";
7
+ export * from "./stat.js";
8
+ export * from "./sync.js";
@@ -1,52 +1,98 @@
1
- import type { BufferedReadableStream, WritableStreamDefaultWriter } from '@yume-chan/stream-extra';
2
- import Struct from '@yume-chan/struct';
1
+ import Struct from "@yume-chan/struct";
3
2
 
4
- import { AdbSyncRequestId, adbSyncWriteRequest } from './request.js';
5
- import { adbSyncReadResponses, AdbSyncResponseId } from './response.js';
6
- import { AdbSyncLstatResponse, AdbSyncStatResponse, type AdbSyncStat } from './stat.js';
3
+ import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
4
+ import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
5
+ import type { AdbSyncSocket } from "./socket.js";
6
+ import type { AdbSyncStat } from "./stat.js";
7
+ import { AdbSyncLstatResponse, AdbSyncStatResponse } from "./stat.js";
7
8
 
8
9
  export interface AdbSyncEntry extends AdbSyncStat {
9
10
  name: string;
10
11
  }
11
12
 
12
- export const AdbSyncEntryResponse =
13
- new Struct({ littleEndian: true })
14
- .fields(AdbSyncLstatResponse)
15
- .uint32('nameLength')
16
- .string('name', { lengthField: 'nameLength' })
17
- .extra({ id: AdbSyncResponseId.Entry as const });
13
+ export const AdbSyncEntryResponse = new Struct({ littleEndian: true })
14
+ .fields(AdbSyncLstatResponse)
15
+ .uint32("nameLength")
16
+ .string("name", { lengthField: "nameLength" })
17
+ .extra({ id: AdbSyncResponseId.Entry as const });
18
18
 
19
- export type AdbSyncEntryResponse = typeof AdbSyncEntryResponse['TDeserializeResult'];
19
+ export type AdbSyncEntryResponse =
20
+ (typeof AdbSyncEntryResponse)["TDeserializeResult"];
20
21
 
21
- export const AdbSyncEntry2Response =
22
- new Struct({ littleEndian: true })
23
- .fields(AdbSyncStatResponse)
24
- .uint32('nameLength')
25
- .string('name', { lengthField: 'nameLength' })
26
- .extra({ id: AdbSyncResponseId.Entry2 as const });
22
+ export const AdbSyncEntry2Response = new Struct({ littleEndian: true })
23
+ .fields(AdbSyncStatResponse)
24
+ .uint32("nameLength")
25
+ .string("name", { lengthField: "nameLength" })
26
+ .extra({ id: AdbSyncResponseId.Entry2 as const });
27
27
 
28
- export type AdbSyncEntry2Response = typeof AdbSyncEntry2Response['TDeserializeResult'];
28
+ export type AdbSyncEntry2Response =
29
+ (typeof AdbSyncEntry2Response)["TDeserializeResult"];
30
+
31
+ export async function* adbSyncOpenDirV2(
32
+ socket: AdbSyncSocket,
33
+ path: string
34
+ ): AsyncGenerator<AdbSyncEntry2Response, void, void> {
35
+ const locked = await socket.lock();
36
+ try {
37
+ await adbSyncWriteRequest(locked, AdbSyncRequestId.ListV2, path);
38
+ for await (const item of adbSyncReadResponses(
39
+ locked,
40
+ AdbSyncResponseId.Entry2,
41
+ AdbSyncEntry2Response
42
+ )) {
43
+ // `LST2` can return error codes for failed `lstat` calls.
44
+ // `LIST` just ignores them.
45
+ // But they only contain `name` so still pretty useless.
46
+ if (item.error !== 0) {
47
+ continue;
48
+ }
49
+ yield item;
50
+ }
51
+ } finally {
52
+ locked.release();
53
+ }
54
+ }
55
+
56
+ export async function* adbSyncOpenDirV1(
57
+ socket: AdbSyncSocket,
58
+ path: string
59
+ ): AsyncGenerator<AdbSyncEntryResponse, void, void> {
60
+ const locked = await socket.lock();
61
+ try {
62
+ await adbSyncWriteRequest(locked, AdbSyncRequestId.List, path);
63
+ for await (const item of adbSyncReadResponses(
64
+ locked,
65
+ AdbSyncResponseId.Entry,
66
+ AdbSyncEntryResponse
67
+ )) {
68
+ yield item;
69
+ }
70
+ } finally {
71
+ locked.release();
72
+ }
73
+ }
29
74
 
30
75
  export async function* adbSyncOpenDir(
31
- stream: BufferedReadableStream,
32
- writer: WritableStreamDefaultWriter<Uint8Array>,
76
+ socket: AdbSyncSocket,
33
77
  path: string,
34
- v2: boolean,
78
+ v2: boolean
35
79
  ): AsyncGenerator<AdbSyncEntry, void, void> {
36
80
  if (v2) {
37
- await adbSyncWriteRequest(writer, AdbSyncRequestId.List2, path);
38
- yield* adbSyncReadResponses(stream, AdbSyncResponseId.Entry2, AdbSyncEntry2Response);
81
+ yield* adbSyncOpenDirV2(socket, path);
39
82
  } else {
40
- await adbSyncWriteRequest(writer, AdbSyncRequestId.List, path);
41
- for await (const item of adbSyncReadResponses(stream, AdbSyncResponseId.Entry, AdbSyncEntryResponse)) {
83
+ for await (const item of adbSyncOpenDirV1(socket, path)) {
42
84
  // Convert to same format as `AdbSyncEntry2Response` for easier consumption.
43
85
  // However it will add some overhead.
44
86
  yield {
45
87
  mode: item.mode,
46
88
  size: BigInt(item.size),
47
89
  mtime: BigInt(item.mtime),
48
- get type() { return item.type; },
49
- get permission() { return item.permission; },
90
+ get type() {
91
+ return item.type;
92
+ },
93
+ get permission() {
94
+ return item.permission;
95
+ },
50
96
  name: item.name,
51
97
  };
52
98
  }
@@ -1,45 +1,57 @@
1
- import { BufferedReadableStream, ReadableStream, WritableStreamDefaultWriter } from '@yume-chan/stream-extra';
2
- import Struct from '@yume-chan/struct';
1
+ import type { ReadableStream } from "@yume-chan/stream-extra";
2
+ import { PushReadableStream } from "@yume-chan/stream-extra";
3
+ import Struct from "@yume-chan/struct";
3
4
 
4
- import { AdbSyncRequestId, adbSyncWriteRequest } from './request.js';
5
- import { adbSyncReadResponses, AdbSyncResponseId } from './response.js';
5
+ import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
6
+ import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
7
+ import type { AdbSyncSocket } from "./socket.js";
6
8
 
7
- export const AdbSyncDataResponse =
8
- new Struct({ littleEndian: true })
9
- .uint32('dataLength')
10
- .uint8Array('data', { lengthField: 'dataLength' })
11
- .extra({ id: AdbSyncResponseId.Data as const });
9
+ export const AdbSyncDataResponse = new Struct({ littleEndian: true })
10
+ .uint32("dataLength")
11
+ .uint8Array("data", { lengthField: "dataLength" })
12
+ .extra({ id: AdbSyncResponseId.Data as const });
12
13
 
13
- export type AdbSyncDataResponse = typeof AdbSyncDataResponse['TDeserializeResult'];
14
+ export type AdbSyncDataResponse =
15
+ (typeof AdbSyncDataResponse)["TDeserializeResult"];
16
+
17
+ export async function* adbSyncPullGenerator(
18
+ socket: AdbSyncSocket,
19
+ path: string
20
+ ): AsyncGenerator<Uint8Array, void, void> {
21
+ const locked = await socket.lock();
22
+ let done = false;
23
+ try {
24
+ await adbSyncWriteRequest(locked, AdbSyncRequestId.Receive, path);
25
+ for await (const packet of adbSyncReadResponses(
26
+ locked,
27
+ AdbSyncResponseId.Data,
28
+ AdbSyncDataResponse
29
+ )) {
30
+ yield packet.data;
31
+ }
32
+ done = true;
33
+ } finally {
34
+ if (!done) {
35
+ // sync pull can't be cancelled, so we have to read all data
36
+ for await (const packet of adbSyncReadResponses(
37
+ locked,
38
+ AdbSyncResponseId.Data,
39
+ AdbSyncDataResponse
40
+ )) {
41
+ void packet;
42
+ }
43
+ }
44
+ locked.release();
45
+ }
46
+ }
14
47
 
15
48
  export function adbSyncPull(
16
- stream: BufferedReadableStream,
17
- writer: WritableStreamDefaultWriter<Uint8Array>,
18
- path: string,
49
+ socket: AdbSyncSocket,
50
+ path: string
19
51
  ): ReadableStream<Uint8Array> {
20
- let generator!: AsyncGenerator<AdbSyncDataResponse, void, void>;
21
- return new ReadableStream<Uint8Array>({
22
- async start() {
23
- // TODO: If `ReadableStream.from(AsyncGenerator)` is added to spec, use it instead.
24
- await adbSyncWriteRequest(writer, AdbSyncRequestId.Receive, path);
25
- generator = adbSyncReadResponses(stream, AdbSyncResponseId.Data, AdbSyncDataResponse);
26
- },
27
- async pull(controller) {
28
- const { done, value } = await generator.next();
29
- if (done) {
30
- controller.close();
31
- return;
32
- }
33
- controller.enqueue(value.data);
34
- },
35
- cancel() {
36
- try {
37
- generator.return();
38
- } catch { }
39
- throw new Error(`Sync commands can't be canceled.`);
40
- },
41
- }, {
42
- highWaterMark: 16 * 1024,
43
- size(chunk) { return chunk.byteLength; }
52
+ return new PushReadableStream(async (controller) => {
53
+ for await (const data of adbSyncPullGenerator(socket, path)) {
54
+ await controller.enqueue(data);
55
+ }
44
56
  });
45
57
  }