@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,38 +1,44 @@
1
1
  import { PromiseResolver } from "@yume-chan/async";
2
- import { type Disposable } from "@yume-chan/event";
2
+ import type { Disposable } from "@yume-chan/event";
3
+ import type {
4
+ Consumable,
5
+ PushReadableStreamController,
6
+ ReadableStream,
7
+ ReadableWritablePair,
8
+ WritableStream,
9
+ } from "@yume-chan/stream-extra";
3
10
  import {
4
- ChunkStream,
11
+ ConsumableWritableStream,
12
+ DistributionStream,
5
13
  DuplexStreamFactory,
6
14
  PushReadableStream,
7
- WritableStream,
8
15
  pipeFrom,
9
- type PushReadableStreamController,
10
- type ReadableStream,
11
- type ReadableWritablePair,
12
16
  } from "@yume-chan/stream-extra";
13
17
 
14
- import { AdbCommand } from "../packet.js";
18
+ import type { Closeable } from "../adb.js";
15
19
 
16
- import { type AdbPacketDispatcher, type Closeable } from "./dispatcher.js";
20
+ import type { AdbPacketDispatcher } from "./dispatcher.js";
21
+ import { AdbCommand } from "./packet.js";
17
22
 
18
- export interface AdbSocketInfo {
23
+ export interface AdbDaemonSocketInfo {
19
24
  localId: number;
20
25
  remoteId: number;
21
26
 
22
27
  localCreated: boolean;
23
- serviceString: string;
28
+ service: string;
24
29
  }
25
30
 
26
- export interface AdbSocketConstructionOptions extends AdbSocketInfo {
31
+ export interface AdbDaemonSocketConstructionOptions
32
+ extends AdbDaemonSocketInfo {
27
33
  dispatcher: AdbPacketDispatcher;
28
34
 
29
35
  highWaterMark?: number | undefined;
30
36
  }
31
37
 
32
- export class AdbSocketController
38
+ export class AdbDaemonSocketController
33
39
  implements
34
- AdbSocketInfo,
35
- ReadableWritablePair<Uint8Array, Uint8Array>,
40
+ AdbDaemonSocketInfo,
41
+ ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>,
36
42
  Closeable,
37
43
  Disposable
38
44
  {
@@ -41,44 +47,47 @@ export class AdbSocketController
41
47
  public readonly localId!: number;
42
48
  public readonly remoteId!: number;
43
49
  public readonly localCreated!: boolean;
44
- public readonly serviceString!: string;
50
+ public readonly service!: string;
45
51
 
46
- private _duplex: DuplexStreamFactory<Uint8Array, Uint8Array>;
52
+ #duplex: DuplexStreamFactory<Uint8Array, Consumable<Uint8Array>>;
47
53
 
48
- private _readable: ReadableStream<Uint8Array>;
49
- private _readableController!: PushReadableStreamController<Uint8Array>;
54
+ #readable: ReadableStream<Uint8Array>;
55
+ #readableController!: PushReadableStreamController<Uint8Array>;
50
56
  public get readable() {
51
- return this._readable;
57
+ return this.#readable;
52
58
  }
53
59
 
54
- private _writePromise: PromiseResolver<void> | undefined;
55
- public readonly writable: WritableStream<Uint8Array>;
60
+ #writePromise: PromiseResolver<void> | undefined;
61
+ public readonly writable: WritableStream<Consumable<Uint8Array>>;
56
62
 
57
- private _closed = false;
63
+ #closed = false;
58
64
  /**
59
65
  * Whether the socket is half-closed (i.e. the local side initiated the close).
60
66
  *
61
67
  * It's only used by dispatcher to avoid sending another `CLSE` packet to remote.
62
68
  */
63
69
  public get closed() {
64
- return this._closed;
70
+ return this.#closed;
65
71
  }
66
72
 
67
- private _socket: AdbSocket;
73
+ private _socket: AdbDaemonSocket;
68
74
  public get socket() {
69
75
  return this._socket;
70
76
  }
71
77
 
72
- public constructor(options: AdbSocketConstructionOptions) {
78
+ public constructor(options: AdbDaemonSocketConstructionOptions) {
73
79
  Object.assign(this, options);
74
80
 
75
81
  // Check this image to help you understand the stream graph
76
82
  // cspell: disable-next-line
77
83
  // https://www.plantuml.com/plantuml/png/TL0zoeGm4ErpYc3l5JxyS0yWM6mX5j4C6p4cxcJ25ejttuGX88ZftizxUKmJI275pGhXl0PP_UkfK_CAz5Z2hcWsW9Ny2fdU4C1f5aSchFVxA8vJjlTPRhqZzDQMRB7AklwJ0xXtX0ZSKH1h24ghoKAdGY23FhxC4nS2pDvxzIvxb-8THU0XlEQJ-ZB7SnXTAvc_LhOckhMdLBnbtndpb-SB7a8q2SRD_W00
78
84
 
79
- this._duplex = new DuplexStreamFactory<Uint8Array, Uint8Array>({
85
+ this.#duplex = new DuplexStreamFactory<
86
+ Uint8Array,
87
+ Consumable<Uint8Array>
88
+ >({
80
89
  close: async () => {
81
- this._closed = true;
90
+ this.#closed = true;
82
91
 
83
92
  await this.dispatcher.sendPacket(
84
93
  AdbCommand.Close,
@@ -91,14 +100,14 @@ export class AdbSocketController
91
100
  },
92
101
  dispose: () => {
93
102
  // Error out the pending writes
94
- this._writePromise?.reject(new Error("Socket closed"));
103
+ this.#writePromise?.reject(new Error("Socket closed"));
95
104
  },
96
105
  });
97
106
 
98
- this._readable = this._duplex.wrapReadable(
107
+ this.#readable = this.#duplex.wrapReadable(
99
108
  new PushReadableStream(
100
109
  (controller) => {
101
- this._readableController = controller;
110
+ this.#readableController = controller;
102
111
  },
103
112
  {
104
113
  highWaterMark: options.highWaterMark ?? 16 * 1024,
@@ -110,47 +119,47 @@ export class AdbSocketController
110
119
  );
111
120
 
112
121
  this.writable = pipeFrom(
113
- this._duplex.createWritable(
114
- new WritableStream({
122
+ this.#duplex.createWritable(
123
+ new ConsumableWritableStream<Uint8Array>({
115
124
  write: async (chunk) => {
116
125
  // Wait for an ack packet
117
- this._writePromise = new PromiseResolver();
126
+ this.#writePromise = new PromiseResolver();
118
127
  await this.dispatcher.sendPacket(
119
128
  AdbCommand.Write,
120
129
  this.localId,
121
130
  this.remoteId,
122
131
  chunk
123
132
  );
124
- await this._writePromise.promise;
133
+ await this.#writePromise.promise;
125
134
  },
126
135
  })
127
136
  ),
128
- new ChunkStream(this.dispatcher.options.maxPayloadSize)
137
+ new DistributionStream(this.dispatcher.options.maxPayloadSize)
129
138
  );
130
139
 
131
- this._socket = new AdbSocket(this);
140
+ this._socket = new AdbDaemonSocket(this);
132
141
  }
133
142
 
134
- public async enqueue(packet: Uint8Array) {
143
+ public async enqueue(data: Uint8Array) {
135
144
  // Consumer may abort the `ReadableStream` to close the socket,
136
145
  // it's OK to throw away further packets in this case.
137
- if (this._readableController.abortSignal.aborted) {
146
+ if (this.#readableController.abortSignal.aborted) {
138
147
  return;
139
148
  }
140
149
 
141
- await this._readableController.enqueue(packet);
150
+ await this.#readableController.enqueue(data);
142
151
  }
143
152
 
144
153
  public ack() {
145
- this._writePromise?.resolve();
154
+ this.#writePromise?.resolve();
146
155
  }
147
156
 
148
157
  public async close(): Promise<void> {
149
- await this._duplex.close();
158
+ await this.#duplex.close();
150
159
  }
151
160
 
152
161
  public dispose() {
153
- return this._duplex.dispose();
162
+ return this.#duplex.dispose();
154
163
  }
155
164
  }
156
165
 
@@ -162,36 +171,42 @@ export class AdbSocketController
162
171
  * `socket.writable.abort()`, `socket.writable.getWriter().abort()`,
163
172
  * `socket.writable.close()` or `socket.writable.getWriter().close()`.
164
173
  */
165
- export class AdbSocket
166
- implements AdbSocketInfo, ReadableWritablePair<Uint8Array, Uint8Array>
174
+ export class AdbDaemonSocket
175
+ implements
176
+ AdbDaemonSocketInfo,
177
+ ReadableWritablePair<Uint8Array, Consumable<Uint8Array>>
167
178
  {
168
- private _controller: AdbSocketController;
179
+ #controller: AdbDaemonSocketController;
169
180
 
170
181
  public get localId(): number {
171
- return this._controller.localId;
182
+ return this.#controller.localId;
172
183
  }
173
184
  public get remoteId(): number {
174
- return this._controller.remoteId;
185
+ return this.#controller.remoteId;
175
186
  }
176
187
  public get localCreated(): boolean {
177
- return this._controller.localCreated;
188
+ return this.#controller.localCreated;
178
189
  }
179
- public get serviceString(): string {
180
- return this._controller.serviceString;
190
+ public get service(): string {
191
+ return this.#controller.service;
181
192
  }
182
193
 
183
194
  public get readable(): ReadableStream<Uint8Array> {
184
- return this._controller.readable;
195
+ return this.#controller.readable;
196
+ }
197
+ public get writable(): WritableStream<Consumable<Uint8Array>> {
198
+ return this.#controller.writable;
185
199
  }
186
- public get writable(): WritableStream<Uint8Array> {
187
- return this._controller.writable;
200
+
201
+ public get closed(): boolean {
202
+ return this.#controller.closed;
188
203
  }
189
204
 
190
- public constructor(controller: AdbSocketController) {
191
- this._controller = controller;
205
+ public constructor(controller: AdbDaemonSocketController) {
206
+ this.#controller = controller;
192
207
  }
193
208
 
194
209
  public close() {
195
- return this._controller.close();
210
+ return this.#controller.close();
196
211
  }
197
212
  }
@@ -0,0 +1,269 @@
1
+ import { PromiseResolver } from "@yume-chan/async";
2
+ import type { Consumable, ReadableWritablePair } from "@yume-chan/stream-extra";
3
+ import {
4
+ AbortController,
5
+ ConsumableWritableStream,
6
+ WritableStream,
7
+ } from "@yume-chan/stream-extra";
8
+ import type { ValueOrPromise } from "@yume-chan/struct";
9
+ import { decodeUtf8, encodeUtf8 } from "@yume-chan/struct";
10
+
11
+ import type {
12
+ AdbIncomingSocketHandler,
13
+ AdbSocket,
14
+ AdbTransport,
15
+ } from "../adb.js";
16
+ import { AdbBanner } from "../banner.js";
17
+ import { AdbFeature } from "../features.js";
18
+
19
+ import type { AdbAuthenticator, AdbCredentialStore } from "./auth.js";
20
+ import {
21
+ ADB_DEFAULT_AUTHENTICATORS,
22
+ AdbAuthenticationProcessor,
23
+ } from "./auth.js";
24
+ import { AdbPacketDispatcher } from "./dispatcher.js";
25
+ import type { AdbPacketData, AdbPacketInit } from "./packet.js";
26
+ import { AdbCommand, calculateChecksum } from "./packet.js";
27
+
28
+ export const ADB_DAEMON_VERSION_OMIT_CHECKSUM = 0x01000001;
29
+
30
+ interface AdbDaemonAuthenticationOptions {
31
+ serial: string;
32
+ connection: ReadableWritablePair<AdbPacketData, Consumable<AdbPacketInit>>;
33
+ credentialStore: AdbCredentialStore;
34
+ authenticators?: AdbAuthenticator[];
35
+ }
36
+
37
+ interface AdbDaemonSocketConnectorConstructionOptions {
38
+ serial: string;
39
+ connection: ReadableWritablePair<AdbPacketData, Consumable<AdbPacketInit>>;
40
+ version: number;
41
+ maxPayloadSize: number;
42
+ banner: string;
43
+ }
44
+
45
+ export class AdbDaemonTransport implements AdbTransport {
46
+ /**
47
+ * Authenticates the connection and creates an `AdbDaemonTransport` instance
48
+ * that can be used by `Adb` class.
49
+ *
50
+ * If an authentication process failed, it's possible to call `authenticate` again
51
+ * on the same connection. Because every time the device receives a `CNXN` packet,
52
+ * it resets all internal state, and starts a new authentication process.
53
+ */
54
+ public static async authenticate({
55
+ serial,
56
+ connection,
57
+ credentialStore,
58
+ authenticators = ADB_DEFAULT_AUTHENTICATORS,
59
+ }: AdbDaemonAuthenticationOptions): Promise<AdbDaemonTransport> {
60
+ // Initially, set to highest-supported version and payload size.
61
+ let version = 0x01000001;
62
+ // Android 4: 4K, Android 7: 256K, Android 9: 1M
63
+ let maxPayloadSize = 1024 * 1024;
64
+
65
+ const resolver = new PromiseResolver<string>();
66
+ const authProcessor = new AdbAuthenticationProcessor(
67
+ authenticators,
68
+ credentialStore
69
+ );
70
+
71
+ // Here is similar to `AdbPacketDispatcher`,
72
+ // But the received packet types and send packet processing are different.
73
+ const abortController = new AbortController();
74
+ const pipe = connection.readable
75
+ .pipeTo(
76
+ new WritableStream({
77
+ async write(packet) {
78
+ switch (packet.command) {
79
+ case AdbCommand.Connect:
80
+ version = Math.min(version, packet.arg0);
81
+ maxPayloadSize = Math.min(
82
+ maxPayloadSize,
83
+ packet.arg1
84
+ );
85
+ resolver.resolve(decodeUtf8(packet.payload));
86
+ break;
87
+ case AdbCommand.Auth: {
88
+ const response = await authProcessor.process(
89
+ packet
90
+ );
91
+ await sendPacket(response);
92
+ break;
93
+ }
94
+ default:
95
+ // Maybe the previous ADB client exited without reading all packets,
96
+ // so they are still waiting in OS internal buffer.
97
+ // Just ignore them.
98
+ // Because a `Connect` packet will reset the device,
99
+ // Eventually there will be `Connect` and `Auth` response packets.
100
+ break;
101
+ }
102
+ },
103
+ }),
104
+ {
105
+ // Don't cancel the source ReadableStream on AbortSignal abort.
106
+ preventCancel: true,
107
+ signal: abortController.signal,
108
+ }
109
+ )
110
+ .then(
111
+ () => {
112
+ if (resolver.state === "running") {
113
+ resolver.reject(
114
+ new Error("Connection closed unexpectedly")
115
+ );
116
+ }
117
+ },
118
+ (e) => {
119
+ resolver.reject(e);
120
+ }
121
+ );
122
+
123
+ const writer = connection.writable.getWriter();
124
+ async function sendPacket(init: AdbPacketData) {
125
+ // Always send checksum in auth steps
126
+ // Because we don't know if the device needs it or not.
127
+ (init as AdbPacketInit).checksum = calculateChecksum(init.payload);
128
+ (init as AdbPacketInit).magic = init.command ^ 0xffffffff;
129
+ await ConsumableWritableStream.write(writer, init as AdbPacketInit);
130
+ }
131
+
132
+ let banner: string;
133
+ try {
134
+ // https://android.googlesource.com/platform/packages/modules/adb/+/79010dc6d5ca7490c493df800d4421730f5466ca/transport.cpp#1252
135
+ // There are some other feature constants, but some of them are only used by ADB server, not devices (daemons).
136
+ const features = [
137
+ AdbFeature.ShellV2,
138
+ AdbFeature.Cmd,
139
+ AdbFeature.StatV2,
140
+ AdbFeature.ListV2,
141
+ AdbFeature.FixedPushMkdir,
142
+ "apex",
143
+ AdbFeature.Abb,
144
+ // only tells the client the symlink timestamp issue in `adb push --sync` has been fixed.
145
+ // No special handling required.
146
+ "fixed_push_symlink_timestamp",
147
+ AdbFeature.AbbExec,
148
+ "remount_shell",
149
+ "track_app",
150
+ "sendrecv_v2",
151
+ "sendrecv_v2_brotli",
152
+ "sendrecv_v2_lz4",
153
+ "sendrecv_v2_zstd",
154
+ "sendrecv_v2_dry_run_send",
155
+ ].join(",");
156
+
157
+ await sendPacket({
158
+ command: AdbCommand.Connect,
159
+ arg0: version,
160
+ arg1: maxPayloadSize,
161
+ // The terminating `;` is required in formal definition
162
+ // But ADB daemon (all versions) can still work without it
163
+ payload: encodeUtf8(`host::features=${features}`),
164
+ });
165
+
166
+ banner = await resolver.promise;
167
+ } finally {
168
+ // When failed, release locks on `connection` so the caller can try again.
169
+ // When success, also release locks so `AdbPacketDispatcher` can use them.
170
+ abortController.abort();
171
+ writer.releaseLock();
172
+
173
+ // Wait until pipe stops (`ReadableStream` lock released)
174
+ await pipe;
175
+ }
176
+
177
+ return new AdbDaemonTransport({
178
+ serial,
179
+ connection,
180
+ version,
181
+ maxPayloadSize,
182
+ banner,
183
+ });
184
+ }
185
+
186
+ readonly #dispatcher: AdbPacketDispatcher;
187
+
188
+ #serial: string;
189
+ public get serial() {
190
+ return this.#serial;
191
+ }
192
+
193
+ #protocolVersion: number;
194
+ public get protocolVersion() {
195
+ return this.#protocolVersion;
196
+ }
197
+
198
+ #maxPayloadSize: number;
199
+ public get maxPayloadSize() {
200
+ return this.#maxPayloadSize;
201
+ }
202
+
203
+ #banner: AdbBanner;
204
+ public get banner() {
205
+ return this.#banner;
206
+ }
207
+
208
+ public get disconnected() {
209
+ return this.#dispatcher.disconnected;
210
+ }
211
+
212
+ public constructor({
213
+ serial,
214
+ connection,
215
+ version,
216
+ maxPayloadSize,
217
+ banner,
218
+ }: AdbDaemonSocketConnectorConstructionOptions) {
219
+ this.#serial = serial;
220
+ this.#banner = AdbBanner.parse(banner);
221
+
222
+ let calculateChecksum: boolean;
223
+ let appendNullToServiceString: boolean;
224
+ if (version >= ADB_DAEMON_VERSION_OMIT_CHECKSUM) {
225
+ calculateChecksum = false;
226
+ appendNullToServiceString = false;
227
+ } else {
228
+ calculateChecksum = true;
229
+ appendNullToServiceString = true;
230
+ }
231
+
232
+ this.#dispatcher = new AdbPacketDispatcher(connection, {
233
+ calculateChecksum,
234
+ appendNullToServiceString,
235
+ maxPayloadSize,
236
+ });
237
+
238
+ this.#protocolVersion = version;
239
+ this.#maxPayloadSize = maxPayloadSize;
240
+ }
241
+
242
+ public connect(service: string): ValueOrPromise<AdbSocket> {
243
+ return this.#dispatcher.createSocket(service);
244
+ }
245
+
246
+ public addReverseTunnel(
247
+ handler: AdbIncomingSocketHandler,
248
+ address?: string
249
+ ): string {
250
+ if (!address) {
251
+ const id = Math.random().toString().substring(2);
252
+ address = `localabstract:reverse_${id}`;
253
+ }
254
+ this.#dispatcher.addReverseTunnel(address, handler);
255
+ return address;
256
+ }
257
+
258
+ public removeReverseTunnel(address: string): void {
259
+ this.#dispatcher.removeReverseTunnel(address);
260
+ }
261
+
262
+ public clearReverseTunnels(): void {
263
+ this.#dispatcher.clearReverseTunnels();
264
+ }
265
+
266
+ public close(): ValueOrPromise<void> {
267
+ return this.#dispatcher.close();
268
+ }
269
+ }
package/src/features.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  // The order follows
2
2
  // https://android.googlesource.com/platform/packages/modules/adb/+/79010dc6d5ca7490c493df800d4421730f5466ca/transport.cpp#1252
3
- export enum AdbFeatures {
4
- ShellV2 = 'shell_v2',
5
- Cmd = 'cmd',
6
- StatV2 = 'stat_v2',
7
- ListV2 = 'ls_v2',
8
- FixedPushMkdir = 'fixed_push_mkdir',
3
+ export enum AdbFeature {
4
+ ShellV2 = "shell_v2",
5
+ Cmd = "cmd",
6
+ StatV2 = "stat_v2",
7
+ ListV2 = "ls_v2",
8
+ FixedPushMkdir = "fixed_push_mkdir",
9
+ Abb = "abb",
10
+ AbbExec = "abb_exec",
11
+ SendReceiveV2 = "sendrecv_v2",
9
12
  }
package/src/index.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  export * from "./adb.js";
2
- export * from "./auth.js";
3
- export * from "./backend.js";
2
+ export * from "./banner.js";
4
3
  export * from "./commands/index.js";
5
- export * from "./crypto.js";
4
+ export * from "./daemon/index.js";
6
5
  export * from "./features.js";
7
- export * from "./packet.js";
8
- export * from "./socket/index.js";
6
+ export * from "./server/index.js";
9
7
  export * from "./utils/index.js";