@yume-chan/adb 0.0.10 → 0.0.13

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 (342) hide show
  1. package/CHANGELOG.json +50 -0
  2. package/CHANGELOG.md +29 -1
  3. package/LICENSE +1 -1
  4. package/README.md +71 -51
  5. package/esm/adb.d.ts +48 -0
  6. package/esm/adb.d.ts.map +1 -0
  7. package/esm/adb.js +149 -136
  8. package/esm/adb.js.map +1 -1
  9. package/{dts → esm}/auth.d.ts +11 -11
  10. package/esm/auth.d.ts.map +1 -0
  11. package/esm/auth.js +72 -110
  12. package/esm/auth.js.map +1 -1
  13. package/esm/backend.d.ts +9 -0
  14. package/esm/backend.d.ts.map +1 -0
  15. package/{dts → esm}/commands/base.d.ts +1 -1
  16. package/esm/commands/base.d.ts.map +1 -0
  17. package/esm/commands/base.js +1 -0
  18. package/esm/commands/base.js.map +1 -1
  19. package/{dts → esm}/commands/framebuffer.d.ts +3 -3
  20. package/esm/commands/framebuffer.d.ts.map +1 -0
  21. package/esm/commands/framebuffer.js +15 -18
  22. package/esm/commands/framebuffer.js.map +1 -1
  23. package/esm/commands/index.d.ts +9 -0
  24. package/esm/commands/index.d.ts.map +1 -0
  25. package/esm/commands/index.js +8 -8
  26. package/esm/commands/index.js.map +1 -1
  27. package/esm/commands/install.d.ts +4 -0
  28. package/esm/commands/install.d.ts.map +1 -0
  29. package/esm/commands/install.js +19 -13
  30. package/esm/commands/install.js.map +1 -1
  31. package/esm/commands/power.d.ts +23 -0
  32. package/esm/commands/power.d.ts.map +1 -0
  33. package/esm/commands/power.js +45 -0
  34. package/esm/commands/power.js.map +1 -0
  35. package/{dts → esm}/commands/reverse.d.ts +3 -3
  36. package/esm/commands/reverse.d.ts.map +1 -0
  37. package/esm/commands/reverse.js +49 -60
  38. package/esm/commands/reverse.js.map +1 -1
  39. package/esm/commands/subprocess/index.d.ts +56 -0
  40. package/esm/commands/subprocess/index.d.ts.map +1 -0
  41. package/esm/commands/subprocess/index.js +88 -0
  42. package/esm/commands/subprocess/index.js.map +1 -0
  43. package/esm/commands/subprocess/legacy.d.ts +35 -0
  44. package/esm/commands/subprocess/legacy.d.ts.map +1 -0
  45. package/esm/commands/subprocess/legacy.js +53 -0
  46. package/esm/commands/subprocess/legacy.js.map +1 -0
  47. package/esm/commands/subprocess/protocol.d.ts +39 -0
  48. package/esm/commands/subprocess/protocol.d.ts.map +1 -0
  49. package/esm/commands/subprocess/protocol.js +157 -0
  50. package/esm/commands/subprocess/protocol.js.map +1 -0
  51. package/esm/commands/subprocess/protocols/index.d.ts +4 -0
  52. package/esm/commands/subprocess/protocols/index.d.ts.map +1 -0
  53. package/esm/commands/subprocess/protocols/index.js +4 -0
  54. package/esm/commands/subprocess/protocols/index.js.map +1 -0
  55. package/esm/commands/subprocess/protocols/none.d.ts +35 -0
  56. package/esm/commands/subprocess/protocols/none.d.ts.map +1 -0
  57. package/esm/commands/subprocess/protocols/none.js +53 -0
  58. package/esm/commands/subprocess/protocols/none.js.map +1 -0
  59. package/esm/commands/subprocess/protocols/shell.d.ts +39 -0
  60. package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -0
  61. package/esm/commands/subprocess/protocols/shell.js +155 -0
  62. package/esm/commands/subprocess/protocols/shell.js.map +1 -0
  63. package/esm/commands/subprocess/protocols/types.d.ts +50 -0
  64. package/esm/commands/subprocess/protocols/types.d.ts.map +1 -0
  65. package/esm/commands/{shell → subprocess/protocols}/types.js +0 -0
  66. package/esm/commands/subprocess/protocols/types.js.map +1 -0
  67. package/esm/commands/subprocess/types.d.ts +50 -0
  68. package/esm/commands/subprocess/types.d.ts.map +1 -0
  69. package/esm/commands/subprocess/types.js +2 -0
  70. package/esm/commands/{shell → subprocess}/types.js.map +1 -1
  71. package/{dts/commands/shell → esm/commands/subprocess}/utils.d.ts +0 -0
  72. package/esm/commands/subprocess/utils.d.ts.map +1 -0
  73. package/esm/commands/{shell → subprocess}/utils.js +0 -0
  74. package/esm/commands/subprocess/utils.js.map +1 -0
  75. package/esm/commands/sync/index.d.ts +8 -0
  76. package/esm/commands/sync/index.d.ts.map +1 -0
  77. package/esm/commands/sync/index.js +7 -7
  78. package/esm/commands/sync/index.js.map +1 -1
  79. package/esm/commands/sync/list.d.ts +41 -0
  80. package/esm/commands/sync/list.d.ts.map +1 -0
  81. package/esm/commands/sync/list.js +52 -20
  82. package/esm/commands/sync/list.js.map +1 -1
  83. package/esm/commands/sync/pull.d.ts +11 -0
  84. package/esm/commands/sync/pull.d.ts.map +1 -0
  85. package/esm/commands/sync/pull.js +17 -11
  86. package/esm/commands/sync/pull.js.map +1 -1
  87. package/esm/commands/sync/push.d.ts +8 -0
  88. package/esm/commands/sync/push.d.ts.map +1 -0
  89. package/esm/commands/sync/push.js +19 -37
  90. package/esm/commands/sync/push.js.map +1 -1
  91. package/{dts → esm}/commands/sync/request.d.ts +4 -3
  92. package/esm/commands/sync/request.d.ts.map +1 -0
  93. package/esm/commands/sync/request.js +25 -27
  94. package/esm/commands/sync/request.js.map +1 -1
  95. package/{dts → esm}/commands/sync/response.d.ts +4 -3
  96. package/esm/commands/sync/response.d.ts.map +1 -0
  97. package/esm/commands/sync/response.js +17 -20
  98. package/esm/commands/sync/response.js.map +1 -1
  99. package/{dts → esm}/commands/sync/stat.d.ts +16 -4
  100. package/esm/commands/sync/stat.d.ts.map +1 -0
  101. package/esm/commands/sync/stat.js +38 -30
  102. package/esm/commands/sync/stat.js.map +1 -1
  103. package/esm/commands/sync/sync.d.ts +61 -0
  104. package/esm/commands/sync/sync.d.ts.map +1 -0
  105. package/esm/commands/sync/sync.js +122 -89
  106. package/esm/commands/sync/sync.js.map +1 -1
  107. package/{dts → esm}/commands/tcpip.d.ts +1 -1
  108. package/{dts → esm}/commands/tcpip.d.ts.map +1 -1
  109. package/esm/commands/tcpip.js +14 -19
  110. package/esm/commands/tcpip.js.map +1 -1
  111. package/esm/crypto.d.ts +37 -0
  112. package/esm/crypto.d.ts.map +1 -0
  113. package/esm/crypto.js +77 -62
  114. package/esm/crypto.js.map +1 -1
  115. package/esm/features.d.ts +8 -0
  116. package/esm/features.d.ts.map +1 -0
  117. package/esm/features.js +7 -3
  118. package/esm/features.js.map +1 -1
  119. package/esm/index.d.ts +11 -0
  120. package/esm/index.d.ts.map +1 -0
  121. package/esm/index.js +10 -10
  122. package/esm/index.js.map +1 -1
  123. package/esm/packet.d.ts +47 -0
  124. package/esm/packet.d.ts.map +1 -0
  125. package/esm/packet.js +27 -52
  126. package/esm/packet.js.map +1 -1
  127. package/esm/socket/controller.d.ts +37 -0
  128. package/esm/socket/controller.d.ts.map +1 -0
  129. package/esm/socket/controller.js +52 -66
  130. package/esm/socket/controller.js.map +1 -1
  131. package/esm/socket/dispatcher.d.ts +44 -0
  132. package/esm/socket/dispatcher.d.ts.map +1 -0
  133. package/esm/socket/dispatcher.js +146 -165
  134. package/esm/socket/dispatcher.js.map +1 -1
  135. package/esm/socket/index.d.ts +3 -0
  136. package/esm/socket/index.d.ts.map +1 -0
  137. package/esm/socket/index.js +2 -6
  138. package/esm/socket/index.js.map +1 -1
  139. package/esm/socket/socket.d.ts +46 -0
  140. package/esm/socket/socket.d.ts.map +1 -0
  141. package/esm/socket/socket.js +77 -13
  142. package/esm/socket/socket.js.map +1 -1
  143. package/esm/stream/buffered.d.ts +35 -0
  144. package/esm/stream/buffered.d.ts.map +1 -0
  145. package/esm/stream/buffered.js +123 -0
  146. package/esm/stream/buffered.js.map +1 -0
  147. package/esm/stream/detect.bak.d.ts +240 -0
  148. package/esm/stream/detect.bak.d.ts.map +1 -0
  149. package/esm/stream/detect.bak.js +60 -0
  150. package/esm/stream/detect.bak.js.map +1 -0
  151. package/esm/stream/detect.d.ts +2 -0
  152. package/esm/stream/detect.d.ts.map +1 -0
  153. package/esm/stream/detect.js +5 -0
  154. package/esm/stream/detect.js.map +1 -0
  155. package/esm/stream/detect.native.d.ts +240 -0
  156. package/esm/stream/detect.native.d.ts.map +1 -0
  157. package/esm/stream/detect.native.js +60 -0
  158. package/esm/stream/detect.native.js.map +1 -0
  159. package/esm/stream/detect.polyfill.d.ts +18 -0
  160. package/esm/stream/detect.polyfill.d.ts.map +1 -0
  161. package/esm/stream/detect.polyfill.js +9 -0
  162. package/esm/stream/detect.polyfill.js.map +1 -0
  163. package/esm/stream/index.d.ts +4 -0
  164. package/esm/stream/index.d.ts.map +1 -0
  165. package/esm/stream/index.js +3 -2
  166. package/esm/stream/index.js.map +1 -1
  167. package/esm/stream/transform.d.ts +98 -0
  168. package/esm/stream/transform.d.ts.map +1 -0
  169. package/esm/stream/transform.js +402 -0
  170. package/esm/stream/transform.js.map +1 -0
  171. package/{dts → esm}/utils/auto-reset-event.d.ts +1 -1
  172. package/esm/utils/auto-reset-event.d.ts.map +1 -0
  173. package/esm/utils/auto-reset-event.js +2 -1
  174. package/esm/utils/auto-reset-event.js.map +1 -1
  175. package/esm/utils/base64.d.ts +5 -0
  176. package/esm/utils/base64.d.ts.map +1 -0
  177. package/esm/utils/base64.js +116 -80
  178. package/esm/utils/base64.js.map +1 -1
  179. package/esm/utils/encoding.d.ts +3 -0
  180. package/esm/utils/encoding.d.ts.map +1 -0
  181. package/esm/utils/encoding.js +1 -1
  182. package/esm/utils/encoding.js.map +1 -1
  183. package/esm/utils/index.d.ts +4 -0
  184. package/esm/utils/index.d.ts.map +1 -0
  185. package/esm/utils/index.js +3 -5
  186. package/esm/utils/index.js.map +1 -1
  187. package/package.json +50 -44
  188. package/src/adb.ts +177 -150
  189. package/src/auth.ts +37 -30
  190. package/src/backend.ts +3 -12
  191. package/src/commands/base.ts +1 -1
  192. package/src/commands/framebuffer.ts +4 -4
  193. package/src/commands/index.ts +8 -8
  194. package/src/commands/install.ts +24 -15
  195. package/src/commands/power.ts +54 -0
  196. package/src/commands/reverse.ts +10 -8
  197. package/src/commands/subprocess/index.ts +139 -0
  198. package/src/commands/subprocess/protocols/index.ts +3 -0
  199. package/src/commands/subprocess/protocols/none.ts +68 -0
  200. package/src/commands/subprocess/protocols/shell.ts +190 -0
  201. package/src/commands/subprocess/protocols/types.ts +59 -0
  202. package/src/commands/{shell → subprocess}/utils.ts +0 -0
  203. package/src/commands/sync/index.ts +7 -7
  204. package/src/commands/sync/list.ts +56 -9
  205. package/src/commands/sync/pull.ts +27 -18
  206. package/src/commands/sync/push.ts +25 -30
  207. package/src/commands/sync/request.ts +8 -7
  208. package/src/commands/sync/response.ts +12 -6
  209. package/src/commands/sync/stat.ts +43 -14
  210. package/src/commands/sync/sync.ts +102 -34
  211. package/src/commands/tcpip.ts +3 -3
  212. package/src/crypto.ts +95 -84
  213. package/src/features.ts +6 -2
  214. package/src/index.ts +11 -10
  215. package/src/packet.ts +49 -53
  216. package/src/socket/dispatcher.ts +110 -109
  217. package/src/socket/index.ts +2 -6
  218. package/src/socket/socket.ts +125 -17
  219. package/src/stream/buffered.ts +147 -0
  220. package/src/stream/detect.native.ts +362 -0
  221. package/src/stream/detect.polyfill.ts +28 -0
  222. package/src/stream/detect.ts +5 -0
  223. package/src/stream/index.ts +3 -2
  224. package/src/stream/transform.ts +483 -0
  225. package/src/utils/auto-reset-event.ts +1 -1
  226. package/src/utils/base64.ts +161 -129
  227. package/src/utils/index.ts +3 -5
  228. package/tsconfig.build.json +3 -0
  229. package/tsconfig.build.tsbuildinfo +1 -0
  230. package/tsconfig.test.json +10 -0
  231. package/dts/adb.d.ts +0 -46
  232. package/dts/adb.d.ts.map +0 -1
  233. package/dts/auth.d.ts.map +0 -1
  234. package/dts/backend.d.ts +0 -13
  235. package/dts/backend.d.ts.map +0 -1
  236. package/dts/commands/base.d.ts.map +0 -1
  237. package/dts/commands/demo-mode.d.ts +0 -41
  238. package/dts/commands/demo-mode.d.ts.map +0 -1
  239. package/dts/commands/framebuffer.d.ts.map +0 -1
  240. package/dts/commands/index.d.ts +0 -9
  241. package/dts/commands/index.d.ts.map +0 -1
  242. package/dts/commands/install.d.ts +0 -3
  243. package/dts/commands/install.d.ts.map +0 -1
  244. package/dts/commands/reverse.d.ts.map +0 -1
  245. package/dts/commands/shell/index.d.ts +0 -46
  246. package/dts/commands/shell/index.d.ts.map +0 -1
  247. package/dts/commands/shell/legacy.d.ts +0 -38
  248. package/dts/commands/shell/legacy.d.ts.map +0 -1
  249. package/dts/commands/shell/protocol.d.ts +0 -45
  250. package/dts/commands/shell/protocol.d.ts.map +0 -1
  251. package/dts/commands/shell/types.d.ts +0 -47
  252. package/dts/commands/shell/types.d.ts.map +0 -1
  253. package/dts/commands/shell/utils.d.ts.map +0 -1
  254. package/dts/commands/sync/index.d.ts +0 -8
  255. package/dts/commands/sync/index.d.ts.map +0 -1
  256. package/dts/commands/sync/list.d.ts +0 -17
  257. package/dts/commands/sync/list.d.ts.map +0 -1
  258. package/dts/commands/sync/pull.d.ts +0 -11
  259. package/dts/commands/sync/pull.d.ts.map +0 -1
  260. package/dts/commands/sync/push.d.ts +0 -8
  261. package/dts/commands/sync/push.d.ts.map +0 -1
  262. package/dts/commands/sync/request.d.ts.map +0 -1
  263. package/dts/commands/sync/response.d.ts.map +0 -1
  264. package/dts/commands/sync/stat.d.ts.map +0 -1
  265. package/dts/commands/sync/sync.d.ts +0 -68
  266. package/dts/commands/sync/sync.d.ts.map +0 -1
  267. package/dts/crypto.d.ts +0 -24
  268. package/dts/crypto.d.ts.map +0 -1
  269. package/dts/features.d.ts +0 -6
  270. package/dts/features.d.ts.map +0 -1
  271. package/dts/index.d.ts +0 -11
  272. package/dts/index.d.ts.map +0 -1
  273. package/dts/packet.d.ts +0 -27
  274. package/dts/packet.d.ts.map +0 -1
  275. package/dts/socket/close-event-emitter.d.ts +0 -8
  276. package/dts/socket/close-event-emitter.d.ts.map +0 -1
  277. package/dts/socket/controller.d.ts +0 -43
  278. package/dts/socket/controller.d.ts.map +0 -1
  279. package/dts/socket/data-event-emitter.d.ts +0 -10
  280. package/dts/socket/data-event-emitter.d.ts.map +0 -1
  281. package/dts/socket/dispatcher.d.ts +0 -53
  282. package/dts/socket/dispatcher.d.ts.map +0 -1
  283. package/dts/socket/index.d.ts +0 -7
  284. package/dts/socket/index.d.ts.map +0 -1
  285. package/dts/socket/logger.d.ts +0 -9
  286. package/dts/socket/logger.d.ts.map +0 -1
  287. package/dts/socket/socket.d.ts +0 -22
  288. package/dts/socket/socket.d.ts.map +0 -1
  289. package/dts/stream/buffered-stream.d.ts +0 -28
  290. package/dts/stream/buffered-stream.d.ts.map +0 -1
  291. package/dts/stream/index.d.ts +0 -3
  292. package/dts/stream/index.d.ts.map +0 -1
  293. package/dts/stream/stream.d.ts +0 -15
  294. package/dts/stream/stream.d.ts.map +0 -1
  295. package/dts/utils/auto-reset-event.d.ts.map +0 -1
  296. package/dts/utils/base64.d.ts +0 -7
  297. package/dts/utils/base64.d.ts.map +0 -1
  298. package/dts/utils/chunk.d.ts +0 -3
  299. package/dts/utils/chunk.d.ts.map +0 -1
  300. package/dts/utils/encoding.d.ts +0 -3
  301. package/dts/utils/encoding.d.ts.map +0 -1
  302. package/dts/utils/event-queue.d.ts +0 -35
  303. package/dts/utils/event-queue.d.ts.map +0 -1
  304. package/dts/utils/index.d.ts +0 -6
  305. package/dts/utils/index.d.ts.map +0 -1
  306. package/esm/commands/demo-mode.js +0 -170
  307. package/esm/commands/demo-mode.js.map +0 -1
  308. package/esm/commands/shell/index.js +0 -62
  309. package/esm/commands/shell/index.js.map +0 -1
  310. package/esm/commands/shell/legacy.js +0 -49
  311. package/esm/commands/shell/legacy.js.map +0 -1
  312. package/esm/commands/shell/protocol.js +0 -106
  313. package/esm/commands/shell/protocol.js.map +0 -1
  314. package/esm/commands/shell/utils.js.map +0 -1
  315. package/esm/socket/close-event-emitter.js +0 -28
  316. package/esm/socket/close-event-emitter.js.map +0 -1
  317. package/esm/socket/data-event-emitter.js +0 -25
  318. package/esm/socket/data-event-emitter.js.map +0 -1
  319. package/esm/socket/logger.js +0 -2
  320. package/esm/socket/logger.js.map +0 -1
  321. package/esm/stream/buffered-stream.js +0 -67
  322. package/esm/stream/buffered-stream.js.map +0 -1
  323. package/esm/stream/stream.js +0 -41
  324. package/esm/stream/stream.js.map +0 -1
  325. package/esm/utils/chunk.js +0 -70
  326. package/esm/utils/chunk.js.map +0 -1
  327. package/esm/utils/event-queue.js +0 -104
  328. package/esm/utils/event-queue.js.map +0 -1
  329. package/src/commands/demo-mode.ts +0 -160
  330. package/src/commands/shell/index.ts +0 -87
  331. package/src/commands/shell/legacy.ts +0 -59
  332. package/src/commands/shell/protocol.ts +0 -121
  333. package/src/commands/shell/types.ts +0 -55
  334. package/src/socket/close-event-emitter.ts +0 -28
  335. package/src/socket/controller.ts +0 -105
  336. package/src/socket/data-event-emitter.ts +0 -27
  337. package/src/socket/logger.ts +0 -12
  338. package/src/stream/buffered-stream.ts +0 -92
  339. package/src/stream/stream.ts +0 -50
  340. package/src/utils/chunk.ts +0 -70
  341. package/src/utils/encoding.ts +0 -13
  342. package/src/utils/event-queue.ts +0 -145
@@ -1,111 +1,105 @@
1
- import { AsyncOperationManager } from '@yume-chan/async';
1
+ import { AsyncOperationManager, PromiseResolver } from '@yume-chan/async';
2
2
  import { AutoDisposable, EventEmitter } from '@yume-chan/event';
3
- import { AdbBackend } from '../backend';
4
- import { AdbCommand, AdbPacket, AdbPacketInit } from '../packet';
5
- import { AutoResetEvent, decodeUtf8, encodeUtf8 } from '../utils';
6
- import { AdbSocketController } from './controller';
7
- import { AdbLogger } from './logger';
8
- import { AdbSocket } from './socket';
9
-
10
- export interface AdbPacketReceivedEventArgs {
11
- handled: boolean;
12
-
13
- packet: AdbPacket;
14
- }
3
+ import { AdbCommand, calculateChecksum, type AdbPacketData, type AdbPacketInit } from '../packet.js';
4
+ import { AbortController, WritableStream, WritableStreamDefaultWriter, type ReadableWritablePair } from '../stream/index.js';
5
+ import { decodeUtf8, encodeUtf8 } from '../utils/index.js';
6
+ import { AdbSocket, AdbSocketController } from './socket.js';
15
7
 
16
8
  export interface AdbIncomingSocketEventArgs {
17
9
  handled: boolean;
18
10
 
19
- packet: AdbPacket;
11
+ packet: AdbPacketData;
20
12
 
21
13
  serviceString: string;
22
14
 
23
15
  socket: AdbSocket;
24
16
  }
25
17
 
26
- const EmptyArrayBuffer = new ArrayBuffer(0);
18
+ const EmptyUint8Array = new Uint8Array(0);
19
+
20
+ export interface AdbPacketDispatcherOptions {
21
+ calculateChecksum: boolean;
22
+ /**
23
+ * Before Android 9.0, ADB uses `char*` to parse service string,
24
+ * thus requires a null character to terminate.
25
+ *
26
+ * Usually it should have the same value as `calculateChecksum`.
27
+ */
28
+ appendNullToServiceString: boolean;
29
+ maxPayloadSize: number;
30
+ }
27
31
 
28
32
  export class AdbPacketDispatcher extends AutoDisposable {
29
33
  // ADB socket id starts from 1
30
34
  // (0 means open failed)
31
35
  private readonly initializers = new AsyncOperationManager(1);
32
36
  private readonly sockets = new Map<number, AdbSocketController>();
33
- private readonly sendLock = new AutoResetEvent();
34
- private readonly logger: AdbLogger | undefined;
35
37
 
36
- public readonly backend: AdbBackend;
38
+ private _writer!: WritableStreamDefaultWriter<AdbPacketInit>;
37
39
 
38
- public maxPayloadSize = 0;
39
- public calculateChecksum = true;
40
- public appendNullToServiceString = true;
40
+ public readonly options: AdbPacketDispatcherOptions;
41
41
 
42
- private readonly packetEvent = this.addDisposable(new EventEmitter<AdbPacketReceivedEventArgs>());
43
- public get onPacket() { return this.packetEvent.event; }
42
+ private _disconnected = new PromiseResolver<void>();
43
+ public get disconnected() { return this._disconnected.promise; }
44
44
 
45
45
  private readonly incomingSocketEvent = this.addDisposable(new EventEmitter<AdbIncomingSocketEventArgs>());
46
46
  public get onIncomingSocket() { return this.incomingSocketEvent.event; }
47
47
 
48
- private readonly errorEvent = this.addDisposable(new EventEmitter<Error>());
49
- public get onError() { return this.errorEvent.event; }
48
+ private _abortController = new AbortController();
50
49
 
51
- private _running = false;
52
- public get running() { return this._running; }
53
-
54
- public constructor(backend: AdbBackend, logger?: AdbLogger) {
50
+ public constructor(
51
+ connection: ReadableWritablePair<AdbPacketData, AdbPacketInit>,
52
+ options: AdbPacketDispatcherOptions
53
+ ) {
55
54
  super();
56
55
 
57
- this.backend = backend;
58
- this.logger = logger;
59
- }
60
-
61
- private async receiveLoop() {
62
- try {
63
- while (this._running) {
64
- const packet = await AdbPacket.read(this.backend);
65
- this.logger?.onIncomingPacket?.(packet);
66
-
67
- switch (packet.command) {
68
- case AdbCommand.OK:
69
- this.handleOk(packet);
70
- continue;
71
- case AdbCommand.Close:
72
- await this.handleClose(packet);
73
- continue;
74
- case AdbCommand.Write:
75
- if (this.sockets.has(packet.arg1)) {
76
- await this.sockets.get(packet.arg1)!.dataEvent.fire(packet.payload!);
77
- await this.sendPacket(AdbCommand.OK, packet.arg1, packet.arg0);
56
+ this.options = options;
57
+
58
+ connection.readable
59
+ .pipeTo(new WritableStream({
60
+ write: async (packet) => {
61
+ try {
62
+ switch (packet.command) {
63
+ case AdbCommand.OK:
64
+ this.handleOk(packet);
65
+ return;
66
+ case AdbCommand.Close:
67
+ await this.handleClose(packet);
68
+ return;
69
+ case AdbCommand.Write:
70
+ if (this.sockets.has(packet.arg1)) {
71
+ await this.sockets.get(packet.arg1)!.enqueue(packet.payload);
72
+ await this.sendPacket(AdbCommand.OK, packet.arg1, packet.arg0);
73
+ }
74
+
75
+ // Maybe the device is responding to a packet of last connection
76
+ // Just ignore it
77
+ return;
78
+ case AdbCommand.Open:
79
+ await this.handleOpen(packet);
80
+ return;
78
81
  }
79
-
80
- // Maybe the device is responding to a packet of last connection
81
- // Just ignore it
82
- continue;
83
- case AdbCommand.Open:
84
- await this.handleOpen(packet);
85
- continue;
86
- }
87
-
88
- const args: AdbPacketReceivedEventArgs = {
89
- handled: false,
90
- packet,
91
- };
92
- this.packetEvent.fire(args);
93
- if (!args.handled) {
94
- this.dispose();
95
- throw new Error(`Unhandled packet with command '${packet.command}'`);
96
- }
97
- }
98
- } catch (e) {
99
- if (!this._running) {
100
- // ignore error
101
- return;
102
- }
103
-
104
- this.errorEvent.fire(e as Error);
105
- }
82
+ } catch (e) {
83
+ // Throw error here will stop the pipe
84
+ // But won't close `readable` because of `preventCancel: true`
85
+ throw e;
86
+ }
87
+ },
88
+ }), {
89
+ preventCancel: false,
90
+ signal: this._abortController.signal,
91
+ })
92
+ .then(() => {
93
+ this.dispose();
94
+ }, (e) => {
95
+ this._disconnected.reject(e);
96
+ this.dispose();
97
+ });
98
+
99
+ this._writer = connection.writable.getWriter();
106
100
  }
107
101
 
108
- private handleOk(packet: AdbPacket) {
102
+ private handleOk(packet: AdbPacketData) {
109
103
  if (this.initializers.resolve(packet.arg1, packet.arg0)) {
110
104
  // Device successfully created the socket
111
105
  return;
@@ -123,7 +117,7 @@ export class AdbPacketDispatcher extends AutoDisposable {
123
117
  this.sendPacket(AdbCommand.Close, packet.arg1, packet.arg0);
124
118
  }
125
119
 
126
- private async handleClose(packet: AdbPacket) {
120
+ private async handleClose(packet: AdbPacketData) {
127
121
  // From https://android.googlesource.com/platform/packages/modules/adb/+/65d18e2c1cc48b585811954892311b28a4c3d188/adb.cpp#459
128
122
  /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
129
123
  * a failed OPEN only. However, due to a bug in previous ADB
@@ -153,14 +147,14 @@ export class AdbPacketDispatcher extends AutoDisposable {
153
147
  // Just ignore it
154
148
  }
155
149
 
156
- private async handleOpen(packet: AdbPacket) {
150
+ private async handleOpen(packet: AdbPacketData) {
157
151
  // AsyncOperationManager doesn't support get and skip an ID
158
152
  // Use `add` + `resolve` to simulate this behavior
159
153
  const [localId] = this.initializers.add<number>();
160
154
  this.initializers.resolve(localId, undefined);
161
155
 
162
156
  const remoteId = packet.arg0;
163
- const serviceString = decodeUtf8(packet.payload!);
157
+ const serviceString = decodeUtf8(packet.payload);
164
158
 
165
159
  const controller = new AdbSocketController({
166
160
  dispatcher: this,
@@ -169,13 +163,12 @@ export class AdbPacketDispatcher extends AutoDisposable {
169
163
  localCreated: false,
170
164
  serviceString,
171
165
  });
172
- const socket = new AdbSocket(controller);
173
166
 
174
167
  const args: AdbIncomingSocketEventArgs = {
175
168
  handled: false,
176
169
  packet,
177
170
  serviceString,
178
- socket,
171
+ socket: controller.socket,
179
172
  };
180
173
  this.incomingSocketEvent.fire(args);
181
174
 
@@ -187,19 +180,20 @@ export class AdbPacketDispatcher extends AutoDisposable {
187
180
  }
188
181
  }
189
182
 
190
- public start() {
191
- this._running = true;
192
- this.receiveLoop();
193
- }
194
-
195
183
  public async createSocket(serviceString: string): Promise<AdbSocket> {
196
- if (this.appendNullToServiceString) {
184
+ if (this.options.appendNullToServiceString) {
197
185
  serviceString += '\0';
198
186
  }
199
187
 
200
188
  const [localId, initializer] = this.initializers.add<number>();
201
- await this.sendPacket(AdbCommand.Open, localId, 0, serviceString);
189
+ await this.sendPacket(
190
+ AdbCommand.Open,
191
+ localId,
192
+ 0,
193
+ serviceString
194
+ );
202
195
 
196
+ // Fulfilled by `handleOk`
203
197
  const remoteId = await initializer;
204
198
  const controller = new AdbSocketController({
205
199
  dispatcher: this,
@@ -208,9 +202,9 @@ export class AdbPacketDispatcher extends AutoDisposable {
208
202
  localCreated: true,
209
203
  serviceString,
210
204
  });
211
- this.sockets.set(controller.localId, controller);
205
+ this.sockets.set(localId, controller);
212
206
 
213
- return new AdbSocket(controller);
207
+ return controller.socket;
214
208
  }
215
209
 
216
210
  public sendPacket(packet: AdbPacketInit): Promise<void>;
@@ -218,52 +212,59 @@ export class AdbPacketDispatcher extends AutoDisposable {
218
212
  command: AdbCommand,
219
213
  arg0: number,
220
214
  arg1: number,
221
- payload?: string | ArrayBuffer
215
+ payload?: string | Uint8Array
222
216
  ): Promise<void>;
223
217
  public async sendPacket(
224
218
  packetOrCommand: AdbPacketInit | AdbCommand,
225
219
  arg0?: number,
226
220
  arg1?: number,
227
- payload: string | ArrayBuffer = EmptyArrayBuffer,
221
+ payload: string | Uint8Array = EmptyUint8Array,
228
222
  ): Promise<void> {
229
- let init: AdbPacketInit;
223
+ let init: AdbPacketData;
230
224
  if (arg0 === undefined) {
231
225
  init = packetOrCommand as AdbPacketInit;
232
226
  } else {
227
+ if (typeof payload === 'string') {
228
+ payload = encodeUtf8(payload);
229
+ }
230
+
233
231
  init = {
234
232
  command: packetOrCommand as AdbCommand,
235
233
  arg0: arg0 as number,
236
234
  arg1: arg1 as number,
237
- payload: typeof payload === 'string' ? encodeUtf8(payload) : payload,
235
+ payload,
238
236
  };
239
237
  }
240
238
 
241
239
  if (init.payload &&
242
- init.payload.byteLength > this.maxPayloadSize) {
240
+ init.payload.byteLength > this.options.maxPayloadSize) {
243
241
  throw new Error('payload too large');
244
242
  }
245
243
 
246
- try {
247
- // `AdbPacket.write` writes each packet in two parts
248
- // Use a lock to prevent packets been interlaced
249
- await this.sendLock.wait();
250
-
251
- this.logger?.onOutgoingPacket?.(init);
252
-
253
- await AdbPacket.write(init, this.calculateChecksum, this.backend);
254
- } finally {
255
- this.sendLock.notify();
244
+ if (this.options.calculateChecksum) {
245
+ calculateChecksum(init);
246
+ } else {
247
+ (init as AdbPacketInit).checksum = 0;
256
248
  }
249
+
250
+ await this._writer.write(init as AdbPacketInit);
257
251
  }
258
252
 
259
253
  public override dispose() {
260
- this._running = false;
261
-
262
254
  for (const socket of this.sockets.values()) {
263
255
  socket.dispose();
264
256
  }
265
257
  this.sockets.clear();
266
258
 
259
+ try {
260
+ // Stop pipes
261
+ this._abortController.abort();
262
+ } catch { }
263
+
264
+ this._writer.releaseLock();
265
+
266
+ this._disconnected.resolve();
267
+
267
268
  super.dispose();
268
269
  }
269
270
  }
@@ -1,6 +1,2 @@
1
- export * from './close-event-emitter';
2
- export * from './controller';
3
- export * from './data-event-emitter';
4
- export * from './dispatcher';
5
- export * from './logger';
6
- export * from './socket';
1
+ export * from './socket.js';
2
+ export * from './dispatcher.js';
@@ -1,28 +1,136 @@
1
- import { AdbSocketController, AdbSocketInfo } from './controller';
1
+ import { PromiseResolver } from "@yume-chan/async";
2
+ import { AdbCommand } from '../packet.js';
3
+ import { ChunkStream, DuplexStreamFactory, pipeFrom, type PushReadableStreamController, type ReadableStream, type ReadableWritablePair, type WritableStream } from '../stream/index.js';
4
+ import type { AdbPacketDispatcher } from './dispatcher.js';
2
5
 
3
- export class AdbSocket implements AdbSocketInfo {
4
- private readonly controller: AdbSocketController;
6
+ export interface AdbSocketInfo {
7
+ localId: number;
8
+ remoteId: number;
5
9
 
6
- public get backend() { return this.controller.backend; }
7
- public get localId() { return this.controller.localId; }
8
- public get remoteId() { return this.controller.remoteId; }
9
- public get localCreated() { return this.controller.localCreated; }
10
- public get serviceString() { return this.controller.serviceString; }
10
+ localCreated: boolean;
11
+ serviceString: string;
12
+ }
13
+
14
+ export interface AdbSocketConstructionOptions extends AdbSocketInfo {
15
+ dispatcher: AdbPacketDispatcher;
11
16
 
12
- public get closed() { return this.controller.closed; }
17
+ highWaterMark?: number | undefined;
18
+ }
13
19
 
14
- public get onData() { return this.controller.dataEvent.event; }
15
- public get onClose() { return this.controller.onClose; }
20
+ export class AdbSocketController implements AdbSocketInfo, ReadableWritablePair<Uint8Array, Uint8Array> {
21
+ private readonly dispatcher!: AdbPacketDispatcher;
16
22
 
17
- public constructor(controller: AdbSocketController) {
18
- this.controller = controller;
23
+ public readonly localId!: number;
24
+ public readonly remoteId!: number;
25
+ public readonly localCreated!: boolean;
26
+ public readonly serviceString!: string;
27
+
28
+ private _factory: DuplexStreamFactory<Uint8Array, Uint8Array>;
29
+
30
+ private _readable: ReadableStream<Uint8Array>;
31
+ private _readableController!: PushReadableStreamController<Uint8Array>;
32
+ public get readable() { return this._readable; }
33
+
34
+ private _writePromise: PromiseResolver<void> | undefined;
35
+ public readonly writable: WritableStream<Uint8Array>;
36
+
37
+ private _closed = false;
38
+ public get closed() { return this._closed; }
39
+
40
+ private _socket: AdbSocket;
41
+ public get socket() { return this._socket; }
42
+
43
+ public constructor(options: AdbSocketConstructionOptions) {
44
+ Object.assign(this, options);
45
+
46
+ // Check this image to help you understand the stream graph
47
+ // cspell: disable-next-line
48
+ // https://www.plantuml.com/plantuml/png/TL0zoeGm4ErpYc3l5JxyS0yWM6mX5j4C6p4cxcJ25ejttuGX88ZftizxUKmJI275pGhXl0PP_UkfK_CAz5Z2hcWsW9Ny2fdU4C1f5aSchFVxA8vJjlTPRhqZzDQMRB7AklwJ0xXtX0ZSKH1h24ghoKAdGY23FhxC4nS2pDvxzIvxb-8THU0XlEQJ-ZB7SnXTAvc_LhOckhMdLBnbtndpb-SB7a8q2SRD_W00
49
+
50
+ this._factory = new DuplexStreamFactory<Uint8Array, Uint8Array>({
51
+ close: async () => {
52
+ await this.close();
53
+ },
54
+ });
55
+
56
+ this._readable = this._factory.createPushReadable(controller => {
57
+ this._readableController = controller;
58
+ }, {
59
+ highWaterMark: options.highWaterMark ?? 16 * 1024,
60
+ size(chunk) { return chunk.byteLength; }
61
+ });
62
+
63
+ this.writable = pipeFrom(
64
+ this._factory.createWritable({
65
+ write: async (chunk) => {
66
+ // Wait for an ack packet
67
+ this._writePromise = new PromiseResolver();
68
+ await this.dispatcher.sendPacket(
69
+ AdbCommand.Write,
70
+ this.localId,
71
+ this.remoteId,
72
+ chunk
73
+ );
74
+ await this._writePromise.promise;
75
+ },
76
+ }),
77
+ new ChunkStream(this.dispatcher.options.maxPayloadSize)
78
+ );
79
+
80
+ this._socket = new AdbSocket(this);
81
+ }
82
+
83
+ public async enqueue(packet: Uint8Array) {
84
+ await this._readableController.enqueue(packet);
85
+ }
86
+
87
+ public ack() {
88
+ this._writePromise?.resolve();
89
+ }
90
+
91
+ public async close(): Promise<void> {
92
+ // Error out the pending writes
93
+ this._writePromise?.reject(new Error('Socket closed'));
94
+
95
+ if (!this._closed) {
96
+ this._closed = true;
97
+
98
+ // Only send close packet when `close` is called before `dispose`
99
+ // (the client initiated the close)
100
+ await this.dispatcher.sendPacket(
101
+ AdbCommand.Close,
102
+ this.localId,
103
+ this.remoteId
104
+ );
105
+ }
106
+ }
107
+
108
+ public dispose() {
109
+ this._closed = true;
110
+
111
+ this._factory.close();
112
+
113
+ // Close `writable` side
114
+ this.close();
19
115
  }
116
+ }
20
117
 
21
- public write(data: ArrayBuffer): Promise<void> {
22
- return this.controller.write(data);
118
+ export class AdbSocket implements AdbSocketInfo, ReadableWritablePair<Uint8Array, Uint8Array>{
119
+ private _controller: AdbSocketController;
120
+
121
+ public get localId(): number { return this._controller.localId; }
122
+ public get remoteId(): number { return this._controller.remoteId; }
123
+ public get localCreated(): boolean { return this._controller.localCreated; }
124
+ public get serviceString(): string { return this._controller.serviceString; }
125
+
126
+ public get readable(): ReadableStream<Uint8Array> { return this._controller.readable; }
127
+ public get writable(): WritableStream<Uint8Array> { return this._controller.writable; }
128
+
129
+ public constructor(controller: AdbSocketController) {
130
+ this._controller = controller;
23
131
  }
24
132
 
25
- public close(): Promise<void> {
26
- return this.controller.close();
133
+ public close() {
134
+ return this._controller.close();
27
135
  }
28
136
  }
@@ -0,0 +1,147 @@
1
+ import type { StructAsyncDeserializeStream } from '@yume-chan/struct';
2
+ import type { AdbSocket, AdbSocketInfo } from '../socket/index.js';
3
+ import type { ReadableStream, ReadableStreamDefaultReader } from './detect.js';
4
+ import { PushReadableStream } from "./transform.js";
5
+
6
+ export class BufferedStreamEndedError extends Error {
7
+ public constructor() {
8
+ super('Stream ended');
9
+
10
+ // Fix Error's prototype chain when compiling to ES5
11
+ Object.setPrototypeOf(this, new.target.prototype);
12
+ }
13
+ }
14
+
15
+ export class BufferedStream {
16
+ private buffer: Uint8Array | undefined;
17
+
18
+ protected readonly stream: ReadableStream<Uint8Array>;
19
+
20
+ protected readonly reader: ReadableStreamDefaultReader<Uint8Array>;
21
+
22
+ public constructor(stream: ReadableStream<Uint8Array>) {
23
+ this.stream = stream;
24
+ this.reader = stream.getReader();
25
+ }
26
+
27
+ /**
28
+ *
29
+ * @param length
30
+ * @returns
31
+ */
32
+ public async read(length: number): Promise<Uint8Array> {
33
+ let array: Uint8Array;
34
+ let index: number;
35
+ if (this.buffer) {
36
+ const buffer = this.buffer;
37
+ if (buffer.byteLength > length) {
38
+ this.buffer = buffer.subarray(length);
39
+ return buffer.subarray(0, length);
40
+ }
41
+
42
+ array = new Uint8Array(length);
43
+ array.set(buffer);
44
+ index = buffer.byteLength;
45
+ this.buffer = undefined;
46
+ } else {
47
+ const { done, value } = await this.reader.read();
48
+ if (done) {
49
+ throw new BufferedStreamEndedError();
50
+ }
51
+
52
+ if (value.byteLength === length) {
53
+ return value;
54
+ }
55
+
56
+ if (value.byteLength > length) {
57
+ this.buffer = value.subarray(length);
58
+ return value.subarray(0, length);
59
+ }
60
+
61
+ array = new Uint8Array(length);
62
+ array.set(value);
63
+ index = value.byteLength;
64
+ }
65
+
66
+ while (index < length) {
67
+ const left = length - index;
68
+
69
+ const { done, value } = await this.reader.read();
70
+ if (done) {
71
+ throw new BufferedStreamEndedError();
72
+ }
73
+
74
+ if (value.byteLength === left) {
75
+ array.set(value, index);
76
+ return array;
77
+ }
78
+
79
+ if (value.byteLength > left) {
80
+ array.set(value.subarray(0, left), index);
81
+ this.buffer = value.subarray(left);
82
+ return array;
83
+ }
84
+
85
+ array.set(value, index);
86
+ index += value.byteLength;
87
+ }
88
+
89
+ return array;
90
+ }
91
+
92
+ /**
93
+ * Return a readable stream with unconsumed data (if any) and
94
+ * all data from the wrapped stream.
95
+ * @returns A `ReadableStream`
96
+ */
97
+ public release(): ReadableStream<Uint8Array> {
98
+ if (this.buffer) {
99
+ return new PushReadableStream<Uint8Array>(async controller => {
100
+ // Put the remaining data back to the stream
101
+ await controller.enqueue(this.buffer!);
102
+
103
+ // Manually pipe the stream
104
+ while (true) {
105
+ try {
106
+ const { done, value } = await this.reader.read();
107
+ if (done) {
108
+ controller.close();
109
+ break;
110
+ } else {
111
+ await controller.enqueue(value);
112
+ }
113
+ } catch (e) {
114
+ controller.error(e);
115
+ break;
116
+ }
117
+ }
118
+ });
119
+ } else {
120
+ // Simply release the reader and return the stream
121
+ this.reader.releaseLock();
122
+ return this.stream;
123
+ }
124
+ }
125
+
126
+ public close() {
127
+ this.reader.cancel();
128
+ }
129
+ }
130
+
131
+ export class AdbBufferedStream
132
+ extends BufferedStream
133
+ implements AdbSocketInfo, StructAsyncDeserializeStream {
134
+ protected readonly socket: AdbSocket;
135
+
136
+ public get localId() { return this.socket.localId; }
137
+ public get remoteId() { return this.socket.remoteId; }
138
+ public get localCreated() { return this.socket.localCreated; }
139
+ public get serviceString() { return this.socket.serviceString; }
140
+
141
+ public get writable() { return this.socket.writable; }
142
+
143
+ public constructor(socket: AdbSocket) {
144
+ super(socket.readable);
145
+ this.socket = socket;
146
+ }
147
+ }