@yume-chan/adb 0.0.18 → 0.0.20

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 (241) hide show
  1. package/CHANGELOG.json +54 -0
  2. package/CHANGELOG.md +25 -1
  3. package/README.md +220 -103
  4. package/esm/adb.d.ts +43 -60
  5. package/esm/adb.d.ts.map +1 -1
  6. package/esm/adb.js +68 -249
  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 +6 -6
  13. package/esm/commands/base.d.ts.map +1 -1
  14. package/esm/commands/base.js +8 -8
  15. package/esm/commands/framebuffer.d.ts +53 -53
  16. package/esm/commands/framebuffer.d.ts.map +1 -1
  17. package/esm/commands/framebuffer.js +46 -46
  18. package/esm/commands/framebuffer.js.map +1 -1
  19. package/esm/commands/index.d.ts +7 -8
  20. package/esm/commands/index.d.ts.map +1 -1
  21. package/esm/commands/index.js +7 -8
  22. package/esm/commands/index.js.map +1 -1
  23. package/esm/commands/power.d.ts +22 -22
  24. package/esm/commands/power.js +48 -48
  25. package/esm/commands/reverse.d.ts +40 -28
  26. package/esm/commands/reverse.d.ts.map +1 -1
  27. package/esm/commands/reverse.js +130 -100
  28. package/esm/commands/reverse.js.map +1 -1
  29. package/esm/commands/subprocess/command.d.ts +57 -51
  30. package/esm/commands/subprocess/command.d.ts.map +1 -1
  31. package/esm/commands/subprocess/command.js +86 -80
  32. package/esm/commands/subprocess/command.js.map +1 -1
  33. package/esm/commands/subprocess/index.d.ts +3 -3
  34. package/esm/commands/subprocess/index.js +3 -3
  35. package/esm/commands/subprocess/protocols/index.d.ts +3 -3
  36. package/esm/commands/subprocess/protocols/index.js +3 -3
  37. package/esm/commands/subprocess/protocols/none.d.ts +30 -35
  38. package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
  39. package/esm/commands/subprocess/protocols/none.js +65 -55
  40. package/esm/commands/subprocess/protocols/none.js.map +1 -1
  41. package/esm/commands/subprocess/protocols/shell.d.ts +33 -38
  42. package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
  43. package/esm/commands/subprocess/protocols/shell.js +172 -162
  44. package/esm/commands/subprocess/protocols/shell.js.map +1 -1
  45. package/esm/commands/subprocess/protocols/types.d.ts +48 -49
  46. package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
  47. package/esm/commands/subprocess/protocols/types.js +1 -1
  48. package/esm/commands/subprocess/utils.d.ts +1 -1
  49. package/esm/commands/subprocess/utils.js +18 -18
  50. package/esm/commands/sync/index.d.ts +8 -7
  51. package/esm/commands/sync/index.d.ts.map +1 -1
  52. package/esm/commands/sync/index.js +8 -7
  53. package/esm/commands/sync/index.js.map +1 -1
  54. package/esm/commands/sync/list.d.ts +42 -40
  55. package/esm/commands/sync/list.d.ts.map +1 -1
  56. package/esm/commands/sync/list.js +67 -47
  57. package/esm/commands/sync/list.js.map +1 -1
  58. package/esm/commands/sync/pull.d.ts +13 -11
  59. package/esm/commands/sync/pull.d.ts.map +1 -1
  60. package/esm/commands/sync/pull.js +35 -37
  61. package/esm/commands/sync/pull.js.map +1 -1
  62. package/esm/commands/sync/push.d.ts +57 -7
  63. package/esm/commands/sync/push.d.ts.map +1 -1
  64. package/esm/commands/sync/push.js +89 -22
  65. package/esm/commands/sync/push.js.map +1 -1
  66. package/esm/commands/sync/request.d.ts +26 -23
  67. package/esm/commands/sync/request.d.ts.map +1 -1
  68. package/esm/commands/sync/request.js +40 -42
  69. package/esm/commands/sync/request.js.map +1 -1
  70. package/esm/commands/sync/response.d.ts +19 -19
  71. package/esm/commands/sync/response.d.ts.map +1 -1
  72. package/esm/commands/sync/response.js +54 -54
  73. package/esm/commands/sync/response.js.map +1 -1
  74. package/esm/commands/sync/socket.d.ts +22 -0
  75. package/esm/commands/sync/socket.d.ts.map +1 -0
  76. package/esm/commands/sync/socket.js +69 -0
  77. package/esm/commands/sync/socket.js.map +1 -0
  78. package/esm/commands/sync/stat.d.ts +72 -72
  79. package/esm/commands/sync/stat.d.ts.map +1 -1
  80. package/esm/commands/sync/stat.js +116 -104
  81. package/esm/commands/sync/stat.js.map +1 -1
  82. package/esm/commands/sync/sync.d.ts +65 -60
  83. package/esm/commands/sync/sync.d.ts.map +1 -1
  84. package/esm/commands/sync/sync.js +123 -149
  85. package/esm/commands/sync/sync.js.map +1 -1
  86. package/esm/commands/tcpip.d.ts +5 -5
  87. package/esm/commands/tcpip.d.ts.map +1 -1
  88. package/esm/commands/tcpip.js +20 -18
  89. package/esm/commands/tcpip.js.map +1 -1
  90. package/esm/{auth.d.ts → daemon/auth.d.ts} +50 -51
  91. package/esm/daemon/auth.d.ts.map +1 -0
  92. package/esm/{auth.js → daemon/auth.js} +95 -96
  93. package/esm/daemon/auth.js.map +1 -0
  94. package/esm/daemon/connection.d.ts +11 -0
  95. package/esm/daemon/connection.d.ts.map +1 -0
  96. package/esm/daemon/connection.js +2 -0
  97. package/esm/daemon/connection.js.map +1 -0
  98. package/esm/{crypto.d.ts → daemon/crypto.d.ts} +36 -36
  99. package/esm/daemon/crypto.d.ts.map +1 -0
  100. package/esm/{crypto.js → daemon/crypto.js} +244 -248
  101. package/esm/daemon/crypto.js.map +1 -0
  102. package/esm/daemon/device.d.ts +9 -0
  103. package/esm/daemon/device.d.ts.map +1 -0
  104. package/esm/daemon/device.js +2 -0
  105. package/esm/daemon/device.js.map +1 -0
  106. package/esm/daemon/dispatcher.d.ts +42 -0
  107. package/esm/daemon/dispatcher.d.ts.map +1 -0
  108. package/esm/{socket → daemon}/dispatcher.js +225 -234
  109. package/esm/daemon/dispatcher.js.map +1 -0
  110. package/esm/daemon/index.d.ts +8 -0
  111. package/esm/daemon/index.d.ts.map +1 -0
  112. package/esm/daemon/index.js +8 -0
  113. package/esm/daemon/index.js.map +1 -0
  114. package/esm/{packet.d.ts → daemon/packet.d.ts} +45 -46
  115. package/esm/daemon/packet.d.ts.map +1 -0
  116. package/esm/{packet.js → daemon/packet.js} +43 -48
  117. package/esm/daemon/packet.js.map +1 -0
  118. package/esm/daemon/socket.d.ts +58 -0
  119. package/esm/daemon/socket.d.ts.map +1 -0
  120. package/esm/{socket → daemon}/socket.js +121 -118
  121. package/esm/daemon/socket.js.map +1 -0
  122. package/esm/daemon/transport.d.ts +45 -0
  123. package/esm/daemon/transport.d.ts.map +1 -0
  124. package/esm/daemon/transport.js +184 -0
  125. package/esm/daemon/transport.js.map +1 -0
  126. package/esm/features.d.ts +10 -7
  127. package/esm/features.d.ts.map +1 -1
  128. package/esm/features.js +13 -10
  129. package/esm/features.js.map +1 -1
  130. package/esm/index.d.ts +7 -9
  131. package/esm/index.d.ts.map +1 -1
  132. package/esm/index.js +7 -9
  133. package/esm/index.js.map +1 -1
  134. package/esm/server/client.d.ts +78 -0
  135. package/esm/server/client.d.ts.map +1 -0
  136. package/esm/server/client.js +329 -0
  137. package/esm/server/client.js.map +1 -0
  138. package/esm/server/index.d.ts +3 -0
  139. package/esm/server/index.d.ts.map +1 -0
  140. package/esm/server/index.js +3 -0
  141. package/esm/server/index.js.map +1 -0
  142. package/esm/server/transport.d.ts +19 -0
  143. package/esm/server/transport.d.ts.map +1 -0
  144. package/esm/server/transport.js +44 -0
  145. package/esm/server/transport.js.map +1 -0
  146. package/esm/utils/auto-reset-event.d.ts +8 -9
  147. package/esm/utils/auto-reset-event.d.ts.map +1 -1
  148. package/esm/utils/auto-reset-event.js +33 -33
  149. package/esm/utils/auto-reset-event.js.map +1 -1
  150. package/esm/utils/base64.d.ts +27 -27
  151. package/esm/utils/base64.js +246 -246
  152. package/esm/utils/base64.js.map +1 -1
  153. package/esm/utils/conditional-variable.d.ts +8 -0
  154. package/esm/utils/conditional-variable.d.ts.map +1 -0
  155. package/esm/utils/conditional-variable.js +34 -0
  156. package/esm/utils/conditional-variable.js.map +1 -0
  157. package/esm/utils/hex.d.ts +3 -0
  158. package/esm/utils/hex.d.ts.map +1 -0
  159. package/esm/utils/hex.js +55 -0
  160. package/esm/utils/hex.js.map +1 -0
  161. package/esm/utils/index.d.ts +6 -3
  162. package/esm/utils/index.d.ts.map +1 -1
  163. package/esm/utils/index.js +6 -3
  164. package/esm/utils/index.js.map +1 -1
  165. package/esm/utils/no-op.d.ts +7 -0
  166. package/esm/utils/no-op.d.ts.map +1 -0
  167. package/esm/utils/no-op.js +12 -0
  168. package/esm/utils/no-op.js.map +1 -0
  169. package/package.json +14 -12
  170. package/src/adb.ts +47 -248
  171. package/src/banner.ts +82 -0
  172. package/src/commands/base.ts +1 -1
  173. package/src/commands/framebuffer.ts +4 -4
  174. package/src/commands/index.ts +7 -8
  175. package/src/commands/power.ts +2 -2
  176. package/src/commands/reverse.ts +90 -70
  177. package/src/commands/subprocess/command.ts +12 -4
  178. package/src/commands/subprocess/index.ts +3 -3
  179. package/src/commands/subprocess/protocols/index.ts +3 -3
  180. package/src/commands/subprocess/protocols/none.ts +36 -23
  181. package/src/commands/subprocess/protocols/shell.ts +94 -74
  182. package/src/commands/subprocess/protocols/types.ts +7 -7
  183. package/src/commands/subprocess/utils.ts +1 -1
  184. package/src/commands/sync/index.ts +8 -7
  185. package/src/commands/sync/list.ts +44 -25
  186. package/src/commands/sync/pull.ts +40 -45
  187. package/src/commands/sync/push.ts +158 -39
  188. package/src/commands/sync/request.ts +21 -16
  189. package/src/commands/sync/response.ts +10 -9
  190. package/src/commands/sync/socket.ts +99 -0
  191. package/src/commands/sync/stat.ts +47 -42
  192. package/src/commands/sync/sync.ts +73 -116
  193. package/src/commands/tcpip.ts +9 -7
  194. package/src/{auth.ts → daemon/auth.ts} +24 -23
  195. package/src/{crypto.ts → daemon/crypto.ts} +25 -33
  196. package/src/daemon/device.ts +14 -0
  197. package/src/{socket → daemon}/dispatcher.ts +95 -117
  198. package/src/daemon/index.ts +7 -0
  199. package/src/daemon/packet.ts +75 -0
  200. package/src/{socket → daemon}/socket.ts +71 -56
  201. package/src/daemon/transport.ts +269 -0
  202. package/src/features.ts +9 -6
  203. package/src/index.ts +3 -5
  204. package/src/server/client.ts +476 -0
  205. package/src/server/index.ts +2 -0
  206. package/src/server/transport.ts +77 -0
  207. package/src/utils/auto-reset-event.ts +14 -15
  208. package/src/utils/conditional-variable.ts +45 -0
  209. package/src/utils/hex.ts +58 -0
  210. package/src/utils/index.ts +6 -3
  211. package/src/utils/no-op.ts +12 -0
  212. package/tsconfig.build.json +12 -1
  213. package/tsconfig.build.tsbuildinfo +1 -1
  214. package/esm/auth.d.ts.map +0 -1
  215. package/esm/auth.js.map +0 -1
  216. package/esm/backend.d.ts +0 -9
  217. package/esm/backend.d.ts.map +0 -1
  218. package/esm/backend.js +0 -2
  219. package/esm/backend.js.map +0 -1
  220. package/esm/commands/install.d.ts +0 -4
  221. package/esm/commands/install.d.ts.map +0 -1
  222. package/esm/commands/install.js +0 -29
  223. package/esm/commands/install.js.map +0 -1
  224. package/esm/crypto.d.ts.map +0 -1
  225. package/esm/crypto.js.map +0 -1
  226. package/esm/packet.d.ts.map +0 -1
  227. package/esm/packet.js.map +0 -1
  228. package/esm/socket/dispatcher.d.ts +0 -60
  229. package/esm/socket/dispatcher.d.ts.map +0 -1
  230. package/esm/socket/dispatcher.js.map +0 -1
  231. package/esm/socket/index.d.ts +0 -3
  232. package/esm/socket/index.d.ts.map +0 -1
  233. package/esm/socket/index.js +0 -3
  234. package/esm/socket/index.js.map +0 -1
  235. package/esm/socket/socket.d.ts +0 -60
  236. package/esm/socket/socket.d.ts.map +0 -1
  237. package/esm/socket/socket.js.map +0 -1
  238. package/src/backend.ts +0 -14
  239. package/src/commands/install.ts +0 -40
  240. package/src/packet.ts +0 -90
  241. package/src/socket/index.ts +0 -2
@@ -1,22 +1,22 @@
1
1
  import { AsyncOperationManager, PromiseResolver } from "@yume-chan/async";
2
- import { type RemoveEventListener } from "@yume-chan/event";
2
+ import type {
3
+ Consumable,
4
+ ReadableWritablePair,
5
+ WritableStreamDefaultWriter,
6
+ } from "@yume-chan/stream-extra";
3
7
  import {
4
8
  AbortController,
9
+ ConsumableWritableStream,
5
10
  WritableStream,
6
- type ReadableWritablePair,
7
- type WritableStreamDefaultWriter,
8
11
  } from "@yume-chan/stream-extra";
9
- import { EMPTY_UINT8_ARRAY, type ValueOrPromise } from "@yume-chan/struct";
12
+ import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct";
10
13
 
11
- import {
12
- AdbCommand,
13
- calculateChecksum,
14
- type AdbPacketData,
15
- type AdbPacketInit,
16
- } from "../packet.js";
17
- import { decodeUtf8, encodeUtf8 } from "../utils/index.js";
14
+ import type { AdbIncomingSocketHandler, AdbSocket, Closeable } from "../adb.js";
15
+ import { decodeUtf8, encodeUtf8, unreachable } from "../utils/index.js";
18
16
 
19
- import { AdbSocketController, type AdbSocket } from "./socket.js";
17
+ import type { AdbPacketData, AdbPacketInit } from "./packet.js";
18
+ import { AdbCommand, calculateChecksum } from "./packet.js";
19
+ import { AdbDaemonSocketController } from "./socket.js";
20
20
 
21
21
  export interface AdbPacketDispatcherOptions {
22
22
  calculateChecksum: boolean;
@@ -30,14 +30,6 @@ export interface AdbPacketDispatcherOptions {
30
30
  maxPayloadSize: number;
31
31
  }
32
32
 
33
- export type AdbIncomingSocketHandler = (
34
- socket: AdbSocket
35
- ) => ValueOrPromise<boolean>;
36
-
37
- export interface Closeable {
38
- close(): ValueOrPromise<void>;
39
- }
40
-
41
33
  /**
42
34
  * The dispatcher is the "dumb" part of the connection handling logic.
43
35
  *
@@ -51,28 +43,30 @@ export interface Closeable {
51
43
  export class AdbPacketDispatcher implements Closeable {
52
44
  // ADB socket id starts from 1
53
45
  // (0 means open failed)
54
- private readonly initializers = new AsyncOperationManager(1);
46
+ readonly #initializers = new AsyncOperationManager(1);
55
47
  /**
56
48
  * Socket local ID to the socket controller.
57
49
  */
58
- private readonly sockets = new Map<number, AdbSocketController>();
50
+ readonly #sockets = new Map<number, AdbDaemonSocketController>();
59
51
 
60
- private _writer!: WritableStreamDefaultWriter<AdbPacketInit>;
52
+ #writer: WritableStreamDefaultWriter<Consumable<AdbPacketInit>>;
61
53
 
62
54
  public readonly options: AdbPacketDispatcherOptions;
63
55
 
64
- private _closed = false;
65
- private _disconnected = new PromiseResolver<void>();
56
+ #closed = false;
57
+ #disconnected = new PromiseResolver<void>();
66
58
  public get disconnected() {
67
- return this._disconnected.promise;
59
+ return this.#disconnected.promise;
68
60
  }
69
61
 
70
- private _incomingSocketHandlers: Set<AdbIncomingSocketHandler> = new Set();
71
-
72
- private _abortController = new AbortController();
62
+ #incomingSocketHandlers = new Map<string, AdbIncomingSocketHandler>();
63
+ #readAbortController = new AbortController();
73
64
 
74
65
  public constructor(
75
- connection: ReadableWritablePair<AdbPacketData, AdbPacketInit>,
66
+ connection: ReadableWritablePair<
67
+ AdbPacketData,
68
+ Consumable<AdbPacketInit>
69
+ >,
76
70
  options: AdbPacketDispatcherOptions
77
71
  ) {
78
72
  this.options = options;
@@ -89,8 +83,8 @@ export class AdbPacketDispatcher implements Closeable {
89
83
  await this.handleClose(packet);
90
84
  break;
91
85
  case AdbCommand.Write:
92
- if (this.sockets.has(packet.arg1)) {
93
- await this.sockets
86
+ if (this.#sockets.has(packet.arg1)) {
87
+ await this.#sockets
94
88
  .get(packet.arg1)!
95
89
  .enqueue(packet.payload);
96
90
  await this.sendPacket(
@@ -126,7 +120,7 @@ export class AdbPacketDispatcher implements Closeable {
126
120
  // it's still possible to create another ADB connection.
127
121
  // So don't close `readable` here.
128
122
  preventCancel: true,
129
- signal: this._abortController.signal,
123
+ signal: this.#readAbortController.signal,
130
124
  }
131
125
  )
132
126
  .then(
@@ -134,23 +128,23 @@ export class AdbPacketDispatcher implements Closeable {
134
128
  this.dispose();
135
129
  },
136
130
  (e) => {
137
- if (!this._closed) {
138
- this._disconnected.reject(e);
131
+ if (!this.#closed) {
132
+ this.#disconnected.reject(e);
139
133
  }
140
134
  this.dispose();
141
135
  }
142
136
  );
143
137
 
144
- this._writer = connection.writable.getWriter();
138
+ this.#writer = connection.writable.getWriter();
145
139
  }
146
140
 
147
141
  private handleOk(packet: AdbPacketData) {
148
- if (this.initializers.resolve(packet.arg1, packet.arg0)) {
142
+ if (this.#initializers.resolve(packet.arg1, packet.arg0)) {
149
143
  // Device successfully created the socket
150
144
  return;
151
145
  }
152
146
 
153
- const socket = this.sockets.get(packet.arg1);
147
+ const socket = this.#sockets.get(packet.arg1);
154
148
  if (socket) {
155
149
  // Device has received last `WRTE` to the socket
156
150
  socket.ack();
@@ -166,7 +160,7 @@ export class AdbPacketDispatcher implements Closeable {
166
160
  // If the socket is still pending
167
161
  if (
168
162
  packet.arg0 === 0 &&
169
- this.initializers.reject(
163
+ this.#initializers.reject(
170
164
  packet.arg1,
171
165
  new Error("Socket open failed")
172
166
  )
@@ -187,7 +181,7 @@ export class AdbPacketDispatcher implements Closeable {
187
181
  */
188
182
 
189
183
  // Ignore `arg0` and search for the socket
190
- const socket = this.sockets.get(packet.arg1);
184
+ const socket = this.#sockets.get(packet.arg1);
191
185
  if (socket) {
192
186
  // The device want to close the socket
193
187
  if (!socket.closed) {
@@ -198,7 +192,7 @@ export class AdbPacketDispatcher implements Closeable {
198
192
  );
199
193
  }
200
194
  await socket.dispose();
201
- this.sockets.delete(packet.arg1);
195
+ this.#sockets.delete(packet.arg1);
202
196
  return;
203
197
  }
204
198
 
@@ -207,141 +201,125 @@ export class AdbPacketDispatcher implements Closeable {
207
201
  // the device may also respond with two `CLSE` packets.
208
202
  }
209
203
 
210
- /**
211
- * Add a handler for incoming socket.
212
- * @param handler A function to call with new incoming sockets. It must return `true` if it accepts the socket.
213
- * @returns A function to remove the handler.
214
- */
215
- public onIncomingSocket(
204
+ public addReverseTunnel(
205
+ service: string,
216
206
  handler: AdbIncomingSocketHandler
217
- ): RemoveEventListener {
218
- this._incomingSocketHandlers.add(handler);
219
- const remove = () => {
220
- this._incomingSocketHandlers.delete(handler);
221
- };
222
- remove.dispose = remove;
223
- return remove;
207
+ ) {
208
+ this.#incomingSocketHandlers.set(service, handler);
209
+ }
210
+
211
+ public removeReverseTunnel(address: string) {
212
+ this.#incomingSocketHandlers.delete(address);
213
+ }
214
+
215
+ public clearReverseTunnels() {
216
+ this.#incomingSocketHandlers.clear();
224
217
  }
225
218
 
226
219
  private async handleOpen(packet: AdbPacketData) {
227
220
  // `AsyncOperationManager` doesn't support skipping IDs
228
221
  // Use `add` + `resolve` to simulate this behavior
229
- const [localId] = this.initializers.add<number>();
230
- this.initializers.resolve(localId, undefined);
222
+ const [localId] = this.#initializers.add<number>();
223
+ this.#initializers.resolve(localId, undefined);
231
224
 
232
225
  const remoteId = packet.arg0;
233
- const serviceString = decodeUtf8(packet.payload);
226
+ let service = decodeUtf8(packet.payload);
227
+ if (service.endsWith("\0")) {
228
+ service = service.substring(0, service.length - 1);
229
+ }
234
230
 
235
- const controller = new AdbSocketController({
231
+ const handler = this.#incomingSocketHandlers.get(service);
232
+ if (!handler) {
233
+ await this.sendPacket(AdbCommand.Close, 0, remoteId);
234
+ return;
235
+ }
236
+
237
+ const controller = new AdbDaemonSocketController({
236
238
  dispatcher: this,
237
239
  localId,
238
240
  remoteId,
239
241
  localCreated: false,
240
- serviceString,
242
+ service,
241
243
  });
242
244
 
243
- for (const handler of this._incomingSocketHandlers) {
244
- if (await handler(controller.socket)) {
245
- this.sockets.set(localId, controller);
246
- await this.sendPacket(AdbCommand.OK, localId, remoteId);
247
- return;
248
- }
245
+ try {
246
+ await handler(controller.socket);
247
+ this.#sockets.set(localId, controller);
248
+ await this.sendPacket(AdbCommand.OK, localId, remoteId);
249
+ } catch (e) {
250
+ await this.sendPacket(AdbCommand.Close, 0, remoteId);
249
251
  }
250
-
251
- await this.sendPacket(AdbCommand.Close, 0, remoteId);
252
252
  }
253
253
 
254
- public async createSocket(serviceString: string): Promise<AdbSocket> {
254
+ public async createSocket(service: string): Promise<AdbSocket> {
255
255
  if (this.options.appendNullToServiceString) {
256
- serviceString += "\0";
256
+ service += "\0";
257
257
  }
258
258
 
259
- const [localId, initializer] = this.initializers.add<number>();
260
- await this.sendPacket(AdbCommand.Open, localId, 0, serviceString);
259
+ const [localId, initializer] = this.#initializers.add<number>();
260
+ await this.sendPacket(AdbCommand.Open, localId, 0, service);
261
261
 
262
262
  // Fulfilled by `handleOk`
263
263
  const remoteId = await initializer;
264
- const controller = new AdbSocketController({
264
+ const controller = new AdbDaemonSocketController({
265
265
  dispatcher: this,
266
266
  localId,
267
267
  remoteId,
268
268
  localCreated: true,
269
- serviceString,
269
+ service,
270
270
  });
271
- this.sockets.set(localId, controller);
271
+ this.#sockets.set(localId, controller);
272
272
 
273
273
  return controller.socket;
274
274
  }
275
275
 
276
- public sendPacket(packet: AdbPacketInit): Promise<void>;
277
- public sendPacket(
276
+ public async sendPacket(
278
277
  command: AdbCommand,
279
278
  arg0: number,
280
279
  arg1: number,
281
- payload?: string | Uint8Array
282
- ): Promise<void>;
283
- public async sendPacket(
284
- packetOrCommand: AdbPacketInit | AdbCommand,
285
- arg0?: number,
286
- arg1?: number,
287
280
  payload: string | Uint8Array = EMPTY_UINT8_ARRAY
288
281
  ): 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
- };
282
+ if (typeof payload === "string") {
283
+ payload = encodeUtf8(payload);
303
284
  }
304
285
 
305
- if (
306
- init.payload &&
307
- init.payload.byteLength > this.options.maxPayloadSize
308
- ) {
286
+ if (payload.byteLength > this.options.maxPayloadSize) {
309
287
  throw new Error("payload too large");
310
288
  }
311
289
 
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);
290
+ await ConsumableWritableStream.write(this.#writer, {
291
+ command,
292
+ arg0,
293
+ arg1,
294
+ payload,
295
+ checksum: this.options.calculateChecksum
296
+ ? calculateChecksum(payload)
297
+ : 0,
298
+ magic: command ^ 0xffffffff,
299
+ });
320
300
  }
321
301
 
322
302
  public async close() {
323
303
  // Send `CLSE` packets for all sockets
324
304
  await Promise.all(
325
- Array.from(this.sockets.values(), (socket) => socket.close())
305
+ Array.from(this.#sockets.values(), (socket) => socket.close())
326
306
  );
327
307
 
328
308
  // Stop receiving
329
309
  // It's possible that we haven't received all `CLSE` confirm packets,
330
310
  // but it doesn't matter, the next connection can cope with them.
331
- this._closed = true;
332
- this._abortController.abort();
333
- this._writer.releaseLock();
311
+ this.#closed = true;
312
+ this.#readAbortController.abort();
313
+ this.#writer.releaseLock();
334
314
 
335
315
  // `pipe().then()` will call `dispose`
336
316
  }
337
317
 
338
318
  private dispose() {
339
- for (const socket of this.sockets.values()) {
340
- socket.dispose().catch((e) => {
341
- void e;
342
- });
319
+ for (const socket of this.#sockets.values()) {
320
+ socket.dispose().catch(unreachable);
343
321
  }
344
322
 
345
- this._disconnected.resolve();
323
+ this.#disconnected.resolve();
346
324
  }
347
325
  }
@@ -0,0 +1,7 @@
1
+ export * from "./auth.js";
2
+ export * from "./crypto.js";
3
+ export * from "./device.js";
4
+ export * from "./dispatcher.js";
5
+ export * from "./packet.js";
6
+ export * from "./socket.js";
7
+ export * from "./transport.js";
@@ -0,0 +1,75 @@
1
+ import { ConsumableTransformStream } from "@yume-chan/stream-extra";
2
+ import Struct from "@yume-chan/struct";
3
+
4
+ export enum AdbCommand {
5
+ Auth = 0x48545541, // 'AUTH'
6
+ Close = 0x45534c43, // 'CLSE'
7
+ Connect = 0x4e584e43, // 'CNXN'
8
+ OK = 0x59414b4f, // 'OKAY'
9
+ Open = 0x4e45504f, // 'OPEN'
10
+ Write = 0x45545257, // 'WRTE'
11
+ }
12
+
13
+ export const AdbPacketHeader = new Struct({ littleEndian: true })
14
+ .uint32("command")
15
+ .uint32("arg0")
16
+ .uint32("arg1")
17
+ .uint32("payloadLength")
18
+ .uint32("checksum")
19
+ .int32("magic");
20
+
21
+ export type AdbPacketHeader = (typeof AdbPacketHeader)["TDeserializeResult"];
22
+
23
+ type AdbPacketHeaderInit = (typeof AdbPacketHeader)["TInit"];
24
+
25
+ export const AdbPacket = new Struct({ littleEndian: true })
26
+ .concat(AdbPacketHeader)
27
+ .uint8Array("payload", { lengthField: "payloadLength" });
28
+
29
+ export type AdbPacket = (typeof AdbPacket)["TDeserializeResult"];
30
+
31
+ /**
32
+ * `AdbPacketData` contains all the useful fields of `AdbPacket`.
33
+ *
34
+ * `AdvDaemonConnection#connect` will return a `ReadableStream<AdbPacketData>`,
35
+ * allow each connection to encode `AdbPacket` in different methods.
36
+ *
37
+ * `AdbDaemonConnection#connect` will return a `WritableStream<AdbPacketInit>`,
38
+ * however, `AdbDaemonTransport` will transform `AdbPacketData` to `AdbPacketInit` for you,
39
+ * so `AdbSocket#writable#write` only needs `AdbPacketData`.
40
+ */
41
+ export type AdbPacketData = Omit<
42
+ (typeof AdbPacket)["TInit"],
43
+ "checksum" | "magic"
44
+ >;
45
+
46
+ export type AdbPacketInit = (typeof AdbPacket)["TInit"];
47
+
48
+ export function calculateChecksum(payload: Uint8Array): number {
49
+ return payload.reduce((result, item) => result + item, 0);
50
+ }
51
+
52
+ export class AdbPacketSerializeStream extends ConsumableTransformStream<
53
+ AdbPacketInit,
54
+ Uint8Array
55
+ > {
56
+ public constructor() {
57
+ const headerBuffer = new Uint8Array(AdbPacketHeader.size);
58
+ super({
59
+ transform: async (chunk, controller) => {
60
+ const init = chunk as AdbPacketInit & AdbPacketHeaderInit;
61
+ init.payloadLength = init.payload.byteLength;
62
+
63
+ AdbPacketHeader.serialize(init, headerBuffer);
64
+ await controller.enqueue(headerBuffer);
65
+
66
+ if (init.payload.byteLength) {
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);
71
+ }
72
+ },
73
+ });
74
+ }
75
+ }