@yume-chan/adb 0.0.10 → 0.0.11

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