@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.
Files changed (197) hide show
  1. package/CHANGELOG.json +57 -0
  2. package/CHANGELOG.md +26 -1
  3. package/README.md +222 -103
  4. package/esm/adb.d.ts +28 -45
  5. package/esm/adb.d.ts.map +1 -1
  6. package/esm/adb.js +34 -213
  7. package/esm/adb.js.map +1 -1
  8. package/esm/banner.d.ts +17 -0
  9. package/esm/banner.d.ts.map +1 -0
  10. package/esm/banner.js +67 -0
  11. package/esm/banner.js.map +1 -0
  12. package/esm/commands/base.d.ts.map +1 -1
  13. package/esm/commands/base.js.map +1 -1
  14. package/esm/commands/framebuffer.d.ts +9 -0
  15. package/esm/commands/framebuffer.d.ts.map +1 -1
  16. package/esm/commands/framebuffer.js +27 -3
  17. package/esm/commands/framebuffer.js.map +1 -1
  18. package/esm/commands/power.d.ts +1 -1
  19. package/esm/commands/power.d.ts.map +1 -1
  20. package/esm/commands/power.js +2 -2
  21. package/esm/commands/power.js.map +1 -1
  22. package/esm/commands/reverse.d.ts +17 -18
  23. package/esm/commands/reverse.d.ts.map +1 -1
  24. package/esm/commands/reverse.js +53 -48
  25. package/esm/commands/reverse.js.map +1 -1
  26. package/esm/commands/subprocess/command.d.ts +1 -1
  27. package/esm/commands/subprocess/command.d.ts.map +1 -1
  28. package/esm/commands/subprocess/command.js +15 -13
  29. package/esm/commands/subprocess/command.js.map +1 -1
  30. package/esm/commands/subprocess/protocols/none.d.ts +3 -8
  31. package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
  32. package/esm/commands/subprocess/protocols/none.js +16 -16
  33. package/esm/commands/subprocess/protocols/none.js.map +1 -1
  34. package/esm/commands/subprocess/protocols/shell.d.ts +3 -9
  35. package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
  36. package/esm/commands/subprocess/protocols/shell.js +63 -57
  37. package/esm/commands/subprocess/protocols/shell.js.map +1 -1
  38. package/esm/commands/subprocess/protocols/types.d.ts +1 -2
  39. package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
  40. package/esm/commands/sync/list.js +2 -2
  41. package/esm/commands/sync/push.d.ts +14 -3
  42. package/esm/commands/sync/push.d.ts.map +1 -1
  43. package/esm/commands/sync/push.js +9 -9
  44. package/esm/commands/sync/push.js.map +1 -1
  45. package/esm/commands/sync/request.js +2 -2
  46. package/esm/commands/sync/request.js.map +1 -1
  47. package/esm/commands/sync/response.d.ts +5 -3
  48. package/esm/commands/sync/response.d.ts.map +1 -1
  49. package/esm/commands/sync/response.js +7 -5
  50. package/esm/commands/sync/response.js.map +1 -1
  51. package/esm/commands/sync/socket.d.ts +8 -14
  52. package/esm/commands/sync/socket.d.ts.map +1 -1
  53. package/esm/commands/sync/socket.js +35 -32
  54. package/esm/commands/sync/socket.js.map +1 -1
  55. package/esm/commands/sync/stat.js +4 -4
  56. package/esm/commands/sync/stat.js.map +1 -1
  57. package/esm/commands/sync/sync.d.ts +26 -18
  58. package/esm/commands/sync/sync.d.ts.map +1 -1
  59. package/esm/commands/sync/sync.js +36 -25
  60. package/esm/commands/sync/sync.js.map +1 -1
  61. package/esm/commands/tcpip.d.ts +2 -2
  62. package/esm/commands/tcpip.d.ts.map +1 -1
  63. package/esm/commands/tcpip.js +4 -2
  64. package/esm/commands/tcpip.js.map +1 -1
  65. package/esm/{auth.d.ts → daemon/auth.d.ts} +12 -11
  66. package/esm/daemon/auth.d.ts.map +1 -0
  67. package/esm/{auth.js → daemon/auth.js} +31 -22
  68. package/esm/daemon/auth.js.map +1 -0
  69. package/esm/{crypto.d.ts → daemon/crypto.d.ts} +5 -5
  70. package/esm/daemon/crypto.d.ts.map +1 -0
  71. package/esm/{crypto.js → daemon/crypto.js} +24 -28
  72. package/esm/daemon/crypto.js.map +1 -0
  73. package/esm/{backend.d.ts → daemon/device.d.ts} +2 -2
  74. package/esm/daemon/device.d.ts.map +1 -0
  75. package/esm/daemon/device.js +2 -0
  76. package/esm/daemon/device.js.map +1 -0
  77. package/esm/{socket → daemon}/dispatcher.d.ts +12 -30
  78. package/esm/daemon/dispatcher.d.ts.map +1 -0
  79. package/esm/{socket → daemon}/dispatcher.js +80 -78
  80. package/esm/daemon/dispatcher.js.map +1 -0
  81. package/esm/daemon/index.d.ts +8 -0
  82. package/esm/daemon/index.d.ts.map +1 -0
  83. package/esm/daemon/index.js +8 -0
  84. package/esm/daemon/index.js.map +1 -0
  85. package/esm/{packet.d.ts → daemon/packet.d.ts} +4 -4
  86. package/esm/daemon/packet.d.ts.map +1 -0
  87. package/esm/{packet.js → daemon/packet.js} +2 -2
  88. package/esm/{packet.js.map → daemon/packet.js.map} +1 -1
  89. package/esm/{socket → daemon}/socket.d.ts +15 -19
  90. package/esm/daemon/socket.d.ts.map +1 -0
  91. package/esm/{socket → daemon}/socket.js +49 -42
  92. package/esm/daemon/socket.js.map +1 -0
  93. package/esm/daemon/transport.d.ts +53 -0
  94. package/esm/daemon/transport.d.ts.map +1 -0
  95. package/esm/daemon/transport.js +186 -0
  96. package/esm/daemon/transport.js.map +1 -0
  97. package/esm/features.js +1 -1
  98. package/esm/features.js.map +1 -1
  99. package/esm/index.d.ts +3 -5
  100. package/esm/index.d.ts.map +1 -1
  101. package/esm/index.js +3 -5
  102. package/esm/index.js.map +1 -1
  103. package/esm/server/client.d.ts +78 -0
  104. package/esm/server/client.d.ts.map +1 -0
  105. package/esm/server/client.js +328 -0
  106. package/esm/server/client.js.map +1 -0
  107. package/esm/server/index.d.ts +3 -0
  108. package/esm/server/index.d.ts.map +1 -0
  109. package/esm/server/index.js +3 -0
  110. package/esm/server/index.js.map +1 -0
  111. package/esm/server/transport.d.ts +19 -0
  112. package/esm/server/transport.d.ts.map +1 -0
  113. package/esm/server/transport.js +44 -0
  114. package/esm/server/transport.js.map +1 -0
  115. package/esm/utils/auto-reset-event.d.ts +1 -2
  116. package/esm/utils/auto-reset-event.d.ts.map +1 -1
  117. package/esm/utils/auto-reset-event.js +12 -12
  118. package/esm/utils/auto-reset-event.js.map +1 -1
  119. package/esm/utils/base64.js +5 -5
  120. package/esm/utils/base64.js.map +1 -1
  121. package/esm/utils/conditional-variable.d.ts +1 -2
  122. package/esm/utils/conditional-variable.d.ts.map +1 -1
  123. package/esm/utils/conditional-variable.js +10 -10
  124. package/esm/utils/conditional-variable.js.map +1 -1
  125. package/esm/utils/hex.d.ts +3 -0
  126. package/esm/utils/hex.d.ts.map +1 -0
  127. package/esm/utils/hex.js +55 -0
  128. package/esm/utils/hex.js.map +1 -0
  129. package/esm/utils/index.d.ts +2 -0
  130. package/esm/utils/index.d.ts.map +1 -1
  131. package/esm/utils/index.js +2 -0
  132. package/esm/utils/index.js.map +1 -1
  133. package/esm/utils/no-op.d.ts +7 -0
  134. package/esm/utils/no-op.d.ts.map +1 -0
  135. package/esm/utils/no-op.js +12 -0
  136. package/esm/utils/no-op.js.map +1 -0
  137. package/package.json +12 -12
  138. package/src/adb.ts +75 -274
  139. package/src/banner.ts +82 -0
  140. package/src/commands/base.ts +1 -1
  141. package/src/commands/framebuffer.ts +31 -3
  142. package/src/commands/power.ts +10 -10
  143. package/src/commands/reverse.ts +77 -82
  144. package/src/commands/subprocess/command.ts +24 -25
  145. package/src/commands/subprocess/protocols/none.ts +29 -30
  146. package/src/commands/subprocess/protocols/shell.ts +87 -89
  147. package/src/commands/subprocess/protocols/types.ts +1 -2
  148. package/src/commands/sync/list.ts +7 -7
  149. package/src/commands/sync/pull.ts +4 -4
  150. package/src/commands/sync/push.ts +28 -16
  151. package/src/commands/sync/request.ts +4 -4
  152. package/src/commands/sync/response.ts +13 -11
  153. package/src/commands/sync/socket.ts +48 -46
  154. package/src/commands/sync/stat.ts +5 -5
  155. package/src/commands/sync/sync.ts +55 -43
  156. package/src/commands/tcpip.ts +6 -4
  157. package/src/{auth.ts → daemon/auth.ts} +62 -43
  158. package/src/{crypto.ts → daemon/crypto.ts} +33 -41
  159. package/src/{backend.ts → daemon/device.ts} +1 -1
  160. package/src/{socket → daemon}/dispatcher.ts +103 -109
  161. package/src/daemon/index.ts +7 -0
  162. package/src/{packet.ts → daemon/packet.ts} +6 -6
  163. package/src/{socket → daemon}/socket.ts +77 -67
  164. package/src/daemon/transport.ts +281 -0
  165. package/src/index.ts +3 -5
  166. package/src/server/client.ts +473 -0
  167. package/src/server/index.ts +2 -0
  168. package/src/server/transport.ts +77 -0
  169. package/src/utils/auto-reset-event.ts +16 -16
  170. package/src/utils/base64.ts +5 -5
  171. package/src/utils/conditional-variable.ts +14 -14
  172. package/src/utils/hex.ts +58 -0
  173. package/src/utils/index.ts +2 -0
  174. package/src/utils/no-op.ts +12 -0
  175. package/tsconfig.build.json +12 -1
  176. package/tsconfig.build.tsbuildinfo +1 -1
  177. package/esm/auth.d.ts.map +0 -1
  178. package/esm/auth.js.map +0 -1
  179. package/esm/backend.d.ts.map +0 -1
  180. package/esm/backend.js +0 -2
  181. package/esm/backend.js.map +0 -1
  182. package/esm/commands/install.d.ts +0 -10
  183. package/esm/commands/install.d.ts.map +0 -1
  184. package/esm/commands/install.js +0 -29
  185. package/esm/commands/install.js.map +0 -1
  186. package/esm/crypto.d.ts.map +0 -1
  187. package/esm/crypto.js.map +0 -1
  188. package/esm/packet.d.ts.map +0 -1
  189. package/esm/socket/dispatcher.d.ts.map +0 -1
  190. package/esm/socket/dispatcher.js.map +0 -1
  191. package/esm/socket/index.d.ts +0 -3
  192. package/esm/socket/index.d.ts.map +0 -1
  193. package/esm/socket/index.js +0 -3
  194. package/esm/socket/index.js.map +0 -1
  195. package/esm/socket/socket.d.ts.map +0 -1
  196. package/esm/socket/socket.js.map +0 -1
  197. package/src/socket/index.ts +0 -2
@@ -10,16 +10,14 @@ import {
10
10
  ConsumableWritableStream,
11
11
  PushReadableStream,
12
12
  StructDeserializeStream,
13
- TransformStream,
14
13
  WritableStream,
15
14
  pipeFrom,
16
15
  } from "@yume-chan/stream-extra";
17
16
  import type { StructValueType } from "@yume-chan/struct";
18
17
  import Struct, { placeholder } from "@yume-chan/struct";
19
18
 
20
- import type { Adb } from "../../../adb.js";
19
+ import type { Adb, AdbSocket } from "../../../adb.js";
21
20
  import { AdbFeature } from "../../../features.js";
22
- import type { AdbSocket } from "../../../socket/index.js";
23
21
  import { encodeUtf8 } from "../../../utils/index.js";
24
22
 
25
23
  import type { AdbSubprocessProtocol } from "./types.js";
@@ -62,54 +60,39 @@ class StdinSerializeStream extends ConsumableTransformStream<
62
60
  }
63
61
  }
64
62
 
65
- class StdoutDeserializeStream extends TransformStream<
66
- AdbShellProtocolPacket,
67
- Uint8Array
68
- > {
69
- constructor(type: AdbShellProtocolId.Stdout | AdbShellProtocolId.Stderr) {
70
- super({
71
- transform(chunk, controller) {
72
- if (chunk.id === type) {
73
- controller.enqueue(chunk.data);
74
- }
75
- },
76
- });
77
- }
78
- }
79
-
80
63
  class MultiplexStream<T> {
81
- private _readable: PushReadableStream<T>;
82
- private _readableController!: PushReadableStreamController<T>;
83
- public get readable() {
84
- return this._readable;
64
+ #readable: PushReadableStream<T>;
65
+ #readableController!: PushReadableStreamController<T>;
66
+ get readable() {
67
+ return this.#readable;
85
68
  }
86
69
 
87
- private _activeCount = 0;
70
+ #activeCount = 0;
88
71
 
89
72
  constructor() {
90
- this._readable = new PushReadableStream((controller) => {
91
- this._readableController = controller;
73
+ this.#readable = new PushReadableStream((controller) => {
74
+ this.#readableController = controller;
92
75
  });
93
76
  }
94
77
 
95
- public createWriteable() {
78
+ createWriteable() {
96
79
  return new WritableStream<T>({
97
80
  start: () => {
98
- this._activeCount += 1;
81
+ this.#activeCount += 1;
99
82
  },
100
83
  write: async (chunk) => {
101
- await this._readableController.enqueue(chunk);
84
+ await this.#readableController.enqueue(chunk);
102
85
  },
103
86
  abort: () => {
104
- this._activeCount -= 1;
105
- if (this._activeCount === 0) {
106
- this._readableController.close();
87
+ this.#activeCount -= 1;
88
+ if (this.#activeCount === 0) {
89
+ this.#readableController.close();
107
90
  }
108
91
  },
109
92
  close: () => {
110
- this._activeCount -= 1;
111
- if (this._activeCount === 0) {
112
- this._readableController.close();
93
+ this.#activeCount -= 1;
94
+ if (this.#activeCount === 0) {
95
+ this.#readableController.close();
113
96
  }
114
97
  },
115
98
  });
@@ -125,84 +108,99 @@ class MultiplexStream<T> {
125
108
  * * `resize`: Yes
126
109
  */
127
110
  export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
128
- public static isSupported(adb: Adb) {
111
+ static isSupported(adb: Adb) {
129
112
  return adb.supportsFeature(AdbFeature.ShellV2);
130
113
  }
131
114
 
132
- public static async pty(adb: Adb, command: string) {
115
+ static async pty(adb: Adb, command: string) {
133
116
  // TODO: AdbShellSubprocessProtocol: Support setting `XTERM` environment variable
134
117
  return new AdbSubprocessShellProtocol(
135
- await adb.createSocket(`shell,v2,pty:${command}`)
118
+ await adb.createSocket(`shell,v2,pty:${command}`),
136
119
  );
137
120
  }
138
121
 
139
- public static async raw(adb: Adb, command: string) {
122
+ static async raw(adb: Adb, command: string) {
140
123
  return new AdbSubprocessShellProtocol(
141
- await adb.createSocket(`shell,v2,raw:${command}`)
124
+ await adb.createSocket(`shell,v2,raw:${command}`),
142
125
  );
143
126
  }
144
127
 
145
- private readonly _socket: AdbSocket;
146
- private _socketWriter: WritableStreamDefaultWriter<
128
+ readonly #socket: AdbSocket;
129
+ #socketWriter: WritableStreamDefaultWriter<
147
130
  Consumable<AdbShellProtocolPacketInit>
148
131
  >;
149
132
 
150
- private _stdin: WritableStream<Consumable<Uint8Array>>;
151
- public get stdin() {
152
- return this._stdin;
133
+ #stdin: WritableStream<Consumable<Uint8Array>>;
134
+ get stdin() {
135
+ return this.#stdin;
153
136
  }
154
137
 
155
- private _stdout: ReadableStream<Uint8Array>;
156
- public get stdout() {
157
- return this._stdout;
138
+ #stdout: ReadableStream<Uint8Array>;
139
+ get stdout() {
140
+ return this.#stdout;
158
141
  }
159
142
 
160
- private _stderr: ReadableStream<Uint8Array>;
161
- public get stderr() {
162
- return this._stderr;
143
+ #stderr: ReadableStream<Uint8Array>;
144
+ get stderr() {
145
+ return this.#stderr;
163
146
  }
164
147
 
165
- private readonly _exit = new PromiseResolver<number>();
166
- public get exit() {
167
- return this._exit.promise;
148
+ readonly #exit = new PromiseResolver<number>();
149
+ get exit() {
150
+ return this.#exit.promise;
168
151
  }
169
152
 
170
- public constructor(socket: AdbSocket) {
171
- this._socket = socket;
153
+ constructor(socket: AdbSocket) {
154
+ this.#socket = socket;
172
155
 
173
156
  // Check this image to help you understand the stream graph
174
157
  // cspell: disable-next-line
175
158
  // https://www.plantuml.com/plantuml/png/bL91QiCm4Bpx5SAdv90lb1JISmiw5XzaQKf5PIkiLZIqzEyLSg8ks13gYtOykpFhiOw93N6UGjVDqK7rZsxKqNw0U_NTgVAy4empOy2mm4_olC0VEVEE47GUpnGjKdgXoD76q4GIEpyFhOwP_m28hW0NNzxNUig1_JdW0bA7muFIJDco1daJ_1SAX9bgvoPJPyIkSekhNYctvIGXrCH6tIsPL5fs-s6J5yc9BpWXhKtNdF2LgVYPGM_6GlMwfhWUsIt4lbScANrwlgVVUifPSVi__t44qStnwPvZwobdSmHHlL57p2vFuHS0
176
159
 
177
- // TODO: AdbShellSubprocessProtocol: Optimize stream graph
160
+ let stdoutController!: PushReadableStreamController<Uint8Array>;
161
+ let stderrController!: PushReadableStreamController<Uint8Array>;
162
+ this.#stdout = new PushReadableStream<Uint8Array>((controller) => {
163
+ stdoutController = controller;
164
+ });
165
+ this.#stderr = new PushReadableStream<Uint8Array>((controller) => {
166
+ stderrController = controller;
167
+ });
178
168
 
179
- const [stdout, stderr] = socket.readable
169
+ socket.readable
180
170
  .pipeThrough(new StructDeserializeStream(AdbShellProtocolPacket))
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;
171
+ .pipeTo(
172
+ new WritableStream<AdbShellProtocolPacket>({
173
+ write: async (chunk) => {
174
+ switch (chunk.id) {
175
+ case AdbShellProtocolId.Exit:
176
+ this.#exit.resolve(chunk.data[0]!);
177
+ break;
178
+ case AdbShellProtocolId.Stdout:
179
+ await stdoutController.enqueue(chunk.data);
180
+ break;
181
+ case AdbShellProtocolId.Stderr:
182
+ await stderrController.enqueue(chunk.data);
183
+ break;
194
184
  }
195
- controller.enqueue(chunk);
196
185
  },
197
- })
186
+ }),
198
187
  )
199
- .tee();
200
- this._stdout = stdout.pipeThrough(
201
- new StdoutDeserializeStream(AdbShellProtocolId.Stdout)
202
- );
203
- this._stderr = stderr.pipeThrough(
204
- new StdoutDeserializeStream(AdbShellProtocolId.Stderr)
205
- );
188
+ .then(
189
+ () => {
190
+ stdoutController.close();
191
+ stderrController.close();
192
+ // If `#exit` has already resolved, this will be a no-op
193
+ this.#exit.reject(
194
+ new Error("Socket ended without exit message"),
195
+ );
196
+ },
197
+ (e) => {
198
+ stdoutController.error(e);
199
+ stderrController.error(e);
200
+ // If `#exit` has already resolved, this will be a no-op
201
+ this.#exit.reject(e);
202
+ },
203
+ );
206
204
 
207
205
  const multiplexer = new MultiplexStream<
208
206
  Consumable<AdbShellProtocolPacketInit>
@@ -212,34 +210,34 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
212
210
  new ConsumableTransformStream({
213
211
  async transform(chunk, controller) {
214
212
  await controller.enqueue(
215
- AdbShellProtocolPacket.serialize(chunk)
213
+ AdbShellProtocolPacket.serialize(chunk),
216
214
  );
217
215
  },
218
- })
216
+ }),
219
217
  )
220
218
  .pipeTo(socket.writable);
221
219
 
222
- this._stdin = pipeFrom(
220
+ this.#stdin = pipeFrom(
223
221
  multiplexer.createWriteable(),
224
- new StdinSerializeStream()
222
+ new StdinSerializeStream(),
225
223
  );
226
224
 
227
- this._socketWriter = multiplexer.createWriteable().getWriter();
225
+ this.#socketWriter = multiplexer.createWriteable().getWriter();
228
226
  }
229
227
 
230
- public async resize(rows: number, cols: number) {
231
- await ConsumableWritableStream.write(this._socketWriter, {
228
+ async resize(rows: number, cols: number) {
229
+ await ConsumableWritableStream.write(this.#socketWriter, {
232
230
  id: AdbShellProtocolId.WindowSizeChange,
233
231
  data: encodeUtf8(
234
232
  // The "correct" format is `${rows}x${cols},${x_pixels}x${y_pixels}`
235
233
  // However, according to https://linux.die.net/man/4/tty_ioctl
236
234
  // `x_pixels` and `y_pixels` are unused, so always sending `0` should be fine.
237
- `${rows}x${cols},0x0\0`
235
+ `${rows}x${cols},0x0\0`,
238
236
  ),
239
237
  });
240
238
  }
241
239
 
242
- public kill() {
243
- return this._socket.close();
240
+ kill() {
241
+ return this.#socket.close();
244
242
  }
245
243
  }
@@ -5,8 +5,7 @@ import type {
5
5
  } from "@yume-chan/stream-extra";
6
6
  import type { ValueOrPromise } from "@yume-chan/struct";
7
7
 
8
- import type { Adb } from "../../../adb.js";
9
- import type { AdbSocket } from "../../../socket/index.js";
8
+ import type { Adb, AdbSocket } from "../../../adb.js";
10
9
 
11
10
  export interface AdbSubprocessProtocol {
12
11
  /**
@@ -11,7 +11,7 @@ export interface AdbSyncEntry extends AdbSyncStat {
11
11
  }
12
12
 
13
13
  export const AdbSyncEntryResponse = new Struct({ littleEndian: true })
14
- .fields(AdbSyncLstatResponse)
14
+ .concat(AdbSyncLstatResponse)
15
15
  .uint32("nameLength")
16
16
  .string("name", { lengthField: "nameLength" })
17
17
  .extra({ id: AdbSyncResponseId.Entry as const });
@@ -20,7 +20,7 @@ export type AdbSyncEntryResponse =
20
20
  (typeof AdbSyncEntryResponse)["TDeserializeResult"];
21
21
 
22
22
  export const AdbSyncEntry2Response = new Struct({ littleEndian: true })
23
- .fields(AdbSyncStatResponse)
23
+ .concat(AdbSyncStatResponse)
24
24
  .uint32("nameLength")
25
25
  .string("name", { lengthField: "nameLength" })
26
26
  .extra({ id: AdbSyncResponseId.Entry2 as const });
@@ -30,7 +30,7 @@ export type AdbSyncEntry2Response =
30
30
 
31
31
  export async function* adbSyncOpenDirV2(
32
32
  socket: AdbSyncSocket,
33
- path: string
33
+ path: string,
34
34
  ): AsyncGenerator<AdbSyncEntry2Response, void, void> {
35
35
  const locked = await socket.lock();
36
36
  try {
@@ -38,7 +38,7 @@ export async function* adbSyncOpenDirV2(
38
38
  for await (const item of adbSyncReadResponses(
39
39
  locked,
40
40
  AdbSyncResponseId.Entry2,
41
- AdbSyncEntry2Response
41
+ AdbSyncEntry2Response,
42
42
  )) {
43
43
  // `LST2` can return error codes for failed `lstat` calls.
44
44
  // `LIST` just ignores them.
@@ -55,7 +55,7 @@ export async function* adbSyncOpenDirV2(
55
55
 
56
56
  export async function* adbSyncOpenDirV1(
57
57
  socket: AdbSyncSocket,
58
- path: string
58
+ path: string,
59
59
  ): AsyncGenerator<AdbSyncEntryResponse, void, void> {
60
60
  const locked = await socket.lock();
61
61
  try {
@@ -63,7 +63,7 @@ export async function* adbSyncOpenDirV1(
63
63
  for await (const item of adbSyncReadResponses(
64
64
  locked,
65
65
  AdbSyncResponseId.Entry,
66
- AdbSyncEntryResponse
66
+ AdbSyncEntryResponse,
67
67
  )) {
68
68
  yield item;
69
69
  }
@@ -75,7 +75,7 @@ export async function* adbSyncOpenDirV1(
75
75
  export async function* adbSyncOpenDir(
76
76
  socket: AdbSyncSocket,
77
77
  path: string,
78
- v2: boolean
78
+ v2: boolean,
79
79
  ): AsyncGenerator<AdbSyncEntry, void, void> {
80
80
  if (v2) {
81
81
  yield* adbSyncOpenDirV2(socket, path);
@@ -16,7 +16,7 @@ export type AdbSyncDataResponse =
16
16
 
17
17
  export async function* adbSyncPullGenerator(
18
18
  socket: AdbSyncSocket,
19
- path: string
19
+ path: string,
20
20
  ): AsyncGenerator<Uint8Array, void, void> {
21
21
  const locked = await socket.lock();
22
22
  let done = false;
@@ -25,7 +25,7 @@ export async function* adbSyncPullGenerator(
25
25
  for await (const packet of adbSyncReadResponses(
26
26
  locked,
27
27
  AdbSyncResponseId.Data,
28
- AdbSyncDataResponse
28
+ AdbSyncDataResponse,
29
29
  )) {
30
30
  yield packet.data;
31
31
  }
@@ -36,7 +36,7 @@ export async function* adbSyncPullGenerator(
36
36
  for await (const packet of adbSyncReadResponses(
37
37
  locked,
38
38
  AdbSyncResponseId.Data,
39
- AdbSyncDataResponse
39
+ AdbSyncDataResponse,
40
40
  )) {
41
41
  void packet;
42
42
  }
@@ -47,7 +47,7 @@ export async function* adbSyncPullGenerator(
47
47
 
48
48
  export function adbSyncPull(
49
49
  socket: AdbSyncSocket,
50
- path: string
50
+ path: string,
51
51
  ): ReadableStream<Uint8Array> {
52
52
  return new PushReadableStream(async (controller) => {
53
53
  for await (const data of adbSyncPullGenerator(socket, path)) {
@@ -6,35 +6,34 @@ import {
6
6
  } from "@yume-chan/stream-extra";
7
7
  import Struct, { placeholder } from "@yume-chan/struct";
8
8
 
9
+ import { NOOP } from "../../utils/index.js";
10
+
9
11
  import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
10
12
  import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
11
13
  import type { AdbSyncSocket, AdbSyncSocketLocked } from "./socket.js";
12
14
  import { LinuxFileType } from "./stat.js";
13
15
 
14
- const NOOP = () => {
15
- // no-op
16
- };
17
-
18
16
  export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024;
19
17
 
20
18
  export interface AdbSyncPushV1Options {
21
19
  socket: AdbSyncSocket;
22
20
  filename: string;
23
21
  file: ReadableStream<Consumable<Uint8Array>>;
24
- mode?: number;
22
+ type?: LinuxFileType;
23
+ permission?: number;
25
24
  mtime?: number;
26
25
  packetSize?: number;
27
26
  }
28
27
 
29
28
  export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32(
30
- "unused"
29
+ "unused",
31
30
  );
32
31
 
33
- async function pipeFile(
32
+ async function pipeFileData(
34
33
  locked: AdbSyncSocketLocked,
35
34
  file: ReadableStream<Consumable<Uint8Array>>,
36
35
  packetSize: number,
37
- mtime: number
36
+ mtime: number,
38
37
  ) {
39
38
  // Read and write in parallel,
40
39
  // allow error response to abort the write.
@@ -46,11 +45,11 @@ async function pipeFile(
46
45
  await adbSyncWriteRequest(
47
46
  locked,
48
47
  AdbSyncRequestId.Data,
49
- chunk
48
+ chunk,
50
49
  );
51
50
  },
52
51
  }),
53
- { signal: abortController.signal }
52
+ { signal: abortController.signal },
54
53
  )
55
54
  .then(async () => {
56
55
  await adbSyncWriteRequest(locked, AdbSyncRequestId.Done, mtime);
@@ -60,7 +59,7 @@ async function pipeFile(
60
59
  await adbSyncReadResponse(
61
60
  locked,
62
61
  AdbSyncResponseId.Ok,
63
- AdbSyncOkResponse
62
+ AdbSyncOkResponse,
64
63
  ).catch((e) => {
65
64
  abortController.abort();
66
65
  throw e;
@@ -71,15 +70,17 @@ export async function adbSyncPushV1({
71
70
  socket,
72
71
  filename,
73
72
  file,
74
- mode = (LinuxFileType.File << 12) | 0o666,
73
+ type = LinuxFileType.File,
74
+ permission = 0o666,
75
75
  mtime = (Date.now() / 1000) | 0,
76
76
  packetSize = ADB_SYNC_MAX_PACKET_SIZE,
77
77
  }: AdbSyncPushV1Options) {
78
78
  const locked = await socket.lock();
79
79
  try {
80
+ const mode = (type << 12) | permission;
80
81
  const pathAndMode = `${filename},${mode.toString()}`;
81
82
  await adbSyncWriteRequest(locked, AdbSyncRequestId.Send, pathAndMode);
82
- await pipeFile(locked, file, packetSize, mtime);
83
+ await pipeFileData(locked, file, packetSize, mtime);
83
84
  } finally {
84
85
  locked.release();
85
86
  }
@@ -103,6 +104,12 @@ export enum AdbSyncSendV2Flags {
103
104
  }
104
105
 
105
106
  export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
107
+ /**
108
+ * Don't write the file to disk. Requires the `sendrecv_v2` feature.
109
+ *
110
+ * It was used during ADB development to benchmark the performance of
111
+ * compression algorithms.
112
+ */
106
113
  dryRun?: boolean;
107
114
  }
108
115
 
@@ -115,7 +122,8 @@ export async function adbSyncPushV2({
115
122
  socket,
116
123
  filename,
117
124
  file,
118
- mode = (LinuxFileType.File << 12) | 0o666,
125
+ type = LinuxFileType.File,
126
+ permission = 0o666,
119
127
  mtime = (Date.now() / 1000) | 0,
120
128
  packetSize = ADB_SYNC_MAX_PACKET_SIZE,
121
129
  dryRun = false,
@@ -124,6 +132,7 @@ export async function adbSyncPushV2({
124
132
  try {
125
133
  await adbSyncWriteRequest(locked, AdbSyncRequestId.SendV2, filename);
126
134
 
135
+ const mode = (type << 12) | permission;
127
136
  let flags: AdbSyncSendV2Flags = AdbSyncSendV2Flags.None;
128
137
  if (dryRun) {
129
138
  flags |= AdbSyncSendV2Flags.DryRun;
@@ -133,16 +142,19 @@ export async function adbSyncPushV2({
133
142
  id: AdbSyncRequestId.SendV2,
134
143
  mode,
135
144
  flags,
136
- })
145
+ }),
137
146
  );
138
147
 
139
- await pipeFile(locked, file, packetSize, mtime);
148
+ await pipeFileData(locked, file, packetSize, mtime);
140
149
  } finally {
141
150
  locked.release();
142
151
  }
143
152
  }
144
153
 
145
154
  export interface AdbSyncPushOptions extends AdbSyncPushV2Options {
155
+ /**
156
+ * Whether to use the v2 protocol. Requires the `sendrecv_v2` feature.
157
+ */
146
158
  v2: boolean;
147
159
  }
148
160
 
@@ -20,7 +20,7 @@ export const AdbSyncNumberRequest = new Struct({ littleEndian: true })
20
20
  .uint32("arg");
21
21
 
22
22
  export const AdbSyncDataRequest = new Struct({ littleEndian: true })
23
- .fields(AdbSyncNumberRequest)
23
+ .concat(AdbSyncNumberRequest)
24
24
  .uint8Array("data", { lengthField: "arg" });
25
25
 
26
26
  export interface AdbSyncWritable {
@@ -30,7 +30,7 @@ export interface AdbSyncWritable {
30
30
  export async function adbSyncWriteRequest(
31
31
  writable: AdbSyncWritable,
32
32
  id: AdbSyncRequestId | string,
33
- value: number | string | Uint8Array
33
+ value: number | string | Uint8Array,
34
34
  ): Promise<void> {
35
35
  if (typeof value === "number") {
36
36
  const buffer = AdbSyncNumberRequest.serialize({
@@ -42,12 +42,12 @@ export async function adbSyncWriteRequest(
42
42
  // Let `writable` buffer writes
43
43
  const buffer = encodeUtf8(value);
44
44
  await writable.write(
45
- AdbSyncNumberRequest.serialize({ id, arg: buffer.byteLength })
45
+ AdbSyncNumberRequest.serialize({ id, arg: buffer.byteLength }),
46
46
  );
47
47
  await writable.write(buffer);
48
48
  } else {
49
49
  await writable.write(
50
- AdbSyncNumberRequest.serialize({ id, arg: value.byteLength })
50
+ AdbSyncNumberRequest.serialize({ id, arg: value.byteLength }),
51
51
  );
52
52
  await writable.write(value);
53
53
  }
@@ -1,5 +1,5 @@
1
1
  import type {
2
- StructAsyncDeserializeStream,
2
+ AsyncExactReadable,
3
3
  StructLike,
4
4
  StructValueType,
5
5
  } from "@yume-chan/struct";
@@ -19,19 +19,21 @@ export enum AdbSyncResponseId {
19
19
  Fail = "FAIL",
20
20
  }
21
21
 
22
+ export class AdbSyncError extends Error {}
23
+
22
24
  export const AdbSyncFailResponse = new Struct({ littleEndian: true })
23
25
  .uint32("messageLength")
24
26
  .string("message", { lengthField: "messageLength" })
25
27
  .postDeserialize((object) => {
26
- throw new Error(object.message);
28
+ throw new AdbSyncError(object.message);
27
29
  });
28
30
 
29
31
  export async function adbSyncReadResponse<T>(
30
- stream: StructAsyncDeserializeStream,
32
+ stream: AsyncExactReadable,
31
33
  id: AdbSyncResponseId,
32
- type: StructLike<T>
34
+ type: StructLike<T>,
33
35
  ): Promise<T> {
34
- const actualId = decodeUtf8(await stream.read(4));
36
+ const actualId = decodeUtf8(await stream.readExactly(4));
35
37
  switch (actualId) {
36
38
  case AdbSyncResponseId.Fail:
37
39
  await AdbSyncFailResponse.deserialize(stream);
@@ -44,14 +46,14 @@ export async function adbSyncReadResponse<T>(
44
46
  }
45
47
 
46
48
  export async function* adbSyncReadResponses<
47
- T extends Struct<object, PropertyKey, object, any>
49
+ T extends Struct<object, PropertyKey, object, any>,
48
50
  >(
49
- stream: StructAsyncDeserializeStream,
51
+ stream: AsyncExactReadable,
50
52
  id: AdbSyncResponseId,
51
- type: T
53
+ type: T,
52
54
  ): AsyncGenerator<StructValueType<T>, void, void> {
53
55
  while (true) {
54
- const actualId = decodeUtf8(await stream.read(4));
56
+ const actualId = decodeUtf8(await stream.readExactly(4));
55
57
  switch (actualId) {
56
58
  case AdbSyncResponseId.Fail:
57
59
  await AdbSyncFailResponse.deserialize(stream);
@@ -61,14 +63,14 @@ export async function* adbSyncReadResponses<
61
63
  //
62
64
  // For example, `DONE` responses for `LIST` requests are 16 bytes (same as `DENT` responses),
63
65
  // but `DONE` responses for `STAT` requests are 12 bytes (same as `STAT` responses).
64
- await stream.read(type.size);
66
+ await stream.readExactly(type.size);
65
67
  return;
66
68
  case id:
67
69
  yield await type.deserialize(stream);
68
70
  break;
69
71
  default:
70
72
  throw new Error(
71
- `Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${actualId}'`
73
+ `Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${actualId}'`,
72
74
  );
73
75
  }
74
76
  }