@yume-chan/adb 0.0.9 → 0.0.10

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 (205) hide show
  1. package/CHANGELOG.json +23 -0
  2. package/CHANGELOG.md +16 -0
  3. package/LICENSE +21 -21
  4. package/README.md +227 -257
  5. package/dts/adb.d.ts.map +1 -1
  6. package/dts/auth.d.ts +11 -1
  7. package/dts/auth.d.ts.map +1 -1
  8. package/dts/backend.d.ts +3 -5
  9. package/dts/backend.d.ts.map +1 -1
  10. package/dts/commands/demo-mode.d.ts +3 -3
  11. package/dts/commands/demo-mode.d.ts.map +1 -1
  12. package/dts/commands/reverse.d.ts +2 -2
  13. package/dts/commands/reverse.d.ts.map +1 -1
  14. package/dts/commands/shell/index.d.ts +31 -5
  15. package/dts/commands/shell/index.d.ts.map +1 -1
  16. package/dts/commands/shell/legacy.d.ts +13 -2
  17. package/dts/commands/shell/legacy.d.ts.map +1 -1
  18. package/dts/commands/shell/protocol.d.ts +11 -3
  19. package/dts/commands/shell/protocol.d.ts.map +1 -1
  20. package/dts/commands/shell/types.d.ts +35 -3
  21. package/dts/commands/shell/types.d.ts.map +1 -1
  22. package/dts/commands/sync/request.d.ts +1 -1
  23. package/dts/commands/sync/request.d.ts.map +1 -1
  24. package/dts/commands/sync/response.d.ts +2 -2
  25. package/dts/commands/sync/response.d.ts.map +1 -1
  26. package/dts/commands/sync/sync.d.ts.map +1 -1
  27. package/dts/crypto.d.ts +7 -0
  28. package/dts/crypto.d.ts.map +1 -1
  29. package/dts/packet.d.ts.map +1 -1
  30. package/dts/socket/close-event-emitter.d.ts.map +1 -1
  31. package/dts/socket/controller.d.ts.map +1 -1
  32. package/dts/socket/data-event-emitter.d.ts.map +1 -1
  33. package/dts/socket/dispatcher.d.ts.map +1 -1
  34. package/dts/stream/buffered-stream.d.ts +2 -4
  35. package/dts/stream/buffered-stream.d.ts.map +1 -1
  36. package/dts/utils/encoding.d.ts +3 -0
  37. package/dts/utils/encoding.d.ts.map +1 -0
  38. package/dts/utils/index.d.ts +1 -0
  39. package/dts/utils/index.d.ts.map +1 -1
  40. package/esm/adb.js +3 -2
  41. package/esm/adb.js.map +1 -1
  42. package/esm/auth.js +2 -2
  43. package/esm/auth.js.map +1 -1
  44. package/esm/commands/demo-mode.js +9 -9
  45. package/esm/commands/demo-mode.js.map +1 -1
  46. package/esm/commands/reverse.js +3 -2
  47. package/esm/commands/reverse.js.map +1 -1
  48. package/esm/commands/shell/index.js +28 -18
  49. package/esm/commands/shell/index.js.map +1 -1
  50. package/esm/commands/shell/legacy.js +16 -0
  51. package/esm/commands/shell/legacy.js.map +1 -1
  52. package/esm/commands/shell/protocol.js +36 -9
  53. package/esm/commands/shell/protocol.js.map +1 -1
  54. package/esm/commands/sync/request.js +5 -4
  55. package/esm/commands/sync/request.js.map +1 -1
  56. package/esm/commands/sync/response.js +4 -3
  57. package/esm/commands/sync/response.js.map +1 -1
  58. package/esm/commands/sync/sync.js.map +1 -1
  59. package/esm/crypto.js +7 -2
  60. package/esm/crypto.js.map +1 -1
  61. package/esm/packet.js +12 -14
  62. package/esm/packet.js.map +1 -1
  63. package/esm/socket/close-event-emitter.js.map +1 -1
  64. package/esm/socket/controller.js.map +1 -1
  65. package/esm/socket/data-event-emitter.js.map +1 -1
  66. package/esm/socket/dispatcher.js +7 -7
  67. package/esm/socket/dispatcher.js.map +1 -1
  68. package/esm/stream/buffered-stream.js +0 -6
  69. package/esm/stream/buffered-stream.js.map +1 -1
  70. package/esm/utils/encoding.js +11 -0
  71. package/esm/utils/encoding.js.map +1 -0
  72. package/esm/utils/index.js +1 -0
  73. package/esm/utils/index.js.map +1 -1
  74. package/package.json +44 -51
  75. package/src/adb.ts +243 -242
  76. package/src/auth.ts +166 -156
  77. package/src/backend.ts +20 -24
  78. package/src/commands/base.ts +11 -11
  79. package/src/commands/demo-mode.ts +160 -160
  80. package/src/commands/framebuffer.ts +73 -73
  81. package/src/commands/index.ts +8 -8
  82. package/src/commands/install.ts +21 -21
  83. package/src/commands/reverse.ts +134 -133
  84. package/src/commands/shell/index.ts +87 -68
  85. package/src/commands/shell/legacy.ts +59 -42
  86. package/src/commands/shell/protocol.ts +121 -94
  87. package/src/commands/shell/types.ts +55 -21
  88. package/src/commands/shell/utils.ts +20 -20
  89. package/src/commands/sync/index.ts +7 -7
  90. package/src/commands/sync/list.ts +39 -39
  91. package/src/commands/sync/pull.ts +34 -34
  92. package/src/commands/sync/push.ts +46 -46
  93. package/src/commands/sync/request.ts +49 -48
  94. package/src/commands/sync/response.ts +58 -57
  95. package/src/commands/sync/stat.ts +121 -121
  96. package/src/commands/sync/sync.ts +113 -113
  97. package/src/commands/tcpip.ts +21 -21
  98. package/src/crypto.ts +285 -280
  99. package/src/features.ts +5 -5
  100. package/src/index.ts +10 -10
  101. package/src/packet.ts +84 -89
  102. package/src/socket/close-event-emitter.ts +28 -28
  103. package/src/socket/controller.ts +105 -105
  104. package/src/socket/data-event-emitter.ts +27 -27
  105. package/src/socket/dispatcher.ts +269 -269
  106. package/src/socket/index.ts +6 -6
  107. package/src/socket/logger.ts +12 -12
  108. package/src/socket/socket.ts +28 -28
  109. package/src/stream/buffered-stream.ts +92 -100
  110. package/src/stream/index.ts +2 -2
  111. package/src/stream/stream.ts +50 -50
  112. package/src/utils/auto-reset-event.ts +41 -41
  113. package/src/utils/base64.ts +274 -274
  114. package/src/utils/chunk.ts +70 -70
  115. package/src/utils/encoding.ts +13 -0
  116. package/src/utils/event-queue.ts +145 -145
  117. package/src/utils/index.ts +5 -4
  118. package/cjs/adb.js +0 -205
  119. package/cjs/adb.js.map +0 -1
  120. package/cjs/auth.js +0 -141
  121. package/cjs/auth.js.map +0 -1
  122. package/cjs/backend.js +0 -3
  123. package/cjs/backend.js.map +0 -1
  124. package/cjs/commands/base.js +0 -12
  125. package/cjs/commands/base.js.map +0 -1
  126. package/cjs/commands/demo-mode.js +0 -174
  127. package/cjs/commands/demo-mode.js.map +0 -1
  128. package/cjs/commands/framebuffer.js +0 -66
  129. package/cjs/commands/framebuffer.js.map +0 -1
  130. package/cjs/commands/index.js +0 -12
  131. package/cjs/commands/index.js.map +0 -1
  132. package/cjs/commands/install.js +0 -20
  133. package/cjs/commands/install.js.map +0 -1
  134. package/cjs/commands/reverse.js +0 -105
  135. package/cjs/commands/reverse.js.map +0 -1
  136. package/cjs/commands/shell/index.js +0 -56
  137. package/cjs/commands/shell/index.js.map +0 -1
  138. package/cjs/commands/shell/legacy.js +0 -37
  139. package/cjs/commands/shell/legacy.js.map +0 -1
  140. package/cjs/commands/shell/protocol.js +0 -83
  141. package/cjs/commands/shell/protocol.js.map +0 -1
  142. package/cjs/commands/shell/types.js +0 -3
  143. package/cjs/commands/shell/types.js.map +0 -1
  144. package/cjs/commands/shell/utils.js +0 -23
  145. package/cjs/commands/shell/utils.js.map +0 -1
  146. package/cjs/commands/sync/index.js +0 -11
  147. package/cjs/commands/sync/index.js.map +0 -1
  148. package/cjs/commands/sync/list.js +0 -36
  149. package/cjs/commands/sync/list.js.map +0 -1
  150. package/cjs/commands/sync/pull.js +0 -34
  151. package/cjs/commands/sync/pull.js.map +0 -1
  152. package/cjs/commands/sync/push.js +0 -49
  153. package/cjs/commands/sync/push.js.map +0 -1
  154. package/cjs/commands/sync/request.js +0 -48
  155. package/cjs/commands/sync/request.js.map +0 -1
  156. package/cjs/commands/sync/response.js +0 -53
  157. package/cjs/commands/sync/response.js.map +0 -1
  158. package/cjs/commands/sync/stat.js +0 -109
  159. package/cjs/commands/sync/stat.js.map +0 -1
  160. package/cjs/commands/sync/sync.js +0 -118
  161. package/cjs/commands/sync/sync.js.map +0 -1
  162. package/cjs/commands/tcpip.js +0 -28
  163. package/cjs/commands/tcpip.js.map +0 -1
  164. package/cjs/crypto.js +0 -231
  165. package/cjs/crypto.js.map +0 -1
  166. package/cjs/features.js +0 -10
  167. package/cjs/features.js.map +0 -1
  168. package/cjs/index.js +0 -14
  169. package/cjs/index.js.map +0 -1
  170. package/cjs/packet.js +0 -77
  171. package/cjs/packet.js.map +0 -1
  172. package/cjs/socket/close-event-emitter.js +0 -32
  173. package/cjs/socket/close-event-emitter.js.map +0 -1
  174. package/cjs/socket/controller.js +0 -84
  175. package/cjs/socket/controller.js.map +0 -1
  176. package/cjs/socket/data-event-emitter.js +0 -29
  177. package/cjs/socket/data-event-emitter.js.map +0 -1
  178. package/cjs/socket/dispatcher.js +0 -219
  179. package/cjs/socket/dispatcher.js.map +0 -1
  180. package/cjs/socket/index.js +0 -10
  181. package/cjs/socket/index.js.map +0 -1
  182. package/cjs/socket/logger.js +0 -3
  183. package/cjs/socket/logger.js.map +0 -1
  184. package/cjs/socket/socket.js +0 -24
  185. package/cjs/socket/socket.js.map +0 -1
  186. package/cjs/stream/buffered-stream.js +0 -78
  187. package/cjs/stream/buffered-stream.js.map +0 -1
  188. package/cjs/stream/index.js +0 -6
  189. package/cjs/stream/index.js.map +0 -1
  190. package/cjs/stream/stream.js +0 -45
  191. package/cjs/stream/stream.js.map +0 -1
  192. package/cjs/utils/auto-reset-event.js +0 -37
  193. package/cjs/utils/auto-reset-event.js.map +0 -1
  194. package/cjs/utils/base64.js +0 -210
  195. package/cjs/utils/base64.js.map +0 -1
  196. package/cjs/utils/chunk.js +0 -75
  197. package/cjs/utils/chunk.js.map +0 -1
  198. package/cjs/utils/event-queue.js +0 -108
  199. package/cjs/utils/event-queue.js.map +0 -1
  200. package/cjs/utils/index.js +0 -8
  201. package/cjs/utils/index.js.map +0 -1
  202. package/tsconfig.cjs.json +0 -11
  203. package/tsconfig.esm.json +0 -28
  204. package/tsconfig.esm.tsbuildinfo +0 -1305
  205. package/tsconfig.json +0 -18
@@ -1,269 +1,269 @@
1
- import { AsyncOperationManager } from '@yume-chan/async';
2
- import { AutoDisposable, EventEmitter } from '@yume-chan/event';
3
- import { AdbBackend } from '../backend';
4
- import { AdbCommand, AdbPacket, AdbPacketInit } from '../packet';
5
- import { AutoResetEvent } 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
- }
15
-
16
- export interface AdbIncomingSocketEventArgs {
17
- handled: boolean;
18
-
19
- packet: AdbPacket;
20
-
21
- serviceString: string;
22
-
23
- socket: AdbSocket;
24
- }
25
-
26
- const EmptyArrayBuffer = new ArrayBuffer(0);
27
-
28
- export class AdbPacketDispatcher extends AutoDisposable {
29
- // ADB socket id starts from 1
30
- // (0 means open failed)
31
- 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;
35
-
36
- public readonly backend: AdbBackend;
37
-
38
- public maxPayloadSize = 0;
39
- public calculateChecksum = true;
40
- public appendNullToServiceString = true;
41
-
42
- private readonly packetEvent = this.addDisposable(new EventEmitter<AdbPacketReceivedEventArgs>());
43
- public get onPacket() { return this.packetEvent.event; }
44
-
45
- private readonly incomingSocketEvent = this.addDisposable(new EventEmitter<AdbIncomingSocketEventArgs>());
46
- public get onIncomingSocket() { return this.incomingSocketEvent.event; }
47
-
48
- private readonly errorEvent = this.addDisposable(new EventEmitter<Error>());
49
- public get onError() { return this.errorEvent.event; }
50
-
51
- private _running = false;
52
- public get running() { return this._running; }
53
-
54
- public constructor(backend: AdbBackend, logger?: AdbLogger) {
55
- super();
56
-
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);
78
- }
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);
105
- }
106
- }
107
-
108
- private handleOk(packet: AdbPacket) {
109
- if (this.initializers.resolve(packet.arg1, packet.arg0)) {
110
- // Device successfully created the socket
111
- return;
112
- }
113
-
114
- const socket = this.sockets.get(packet.arg1);
115
- if (socket) {
116
- // Device has received last `WRTE` to the socket
117
- socket.ack();
118
- return;
119
- }
120
-
121
- // Maybe the device is responding to a packet of last connection
122
- // Tell the device to close the socket
123
- this.sendPacket(AdbCommand.Close, packet.arg1, packet.arg0);
124
- }
125
-
126
- private async handleClose(packet: AdbPacket) {
127
- // From https://android.googlesource.com/platform/packages/modules/adb/+/65d18e2c1cc48b585811954892311b28a4c3d188/adb.cpp#459
128
- /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
129
- * a failed OPEN only. However, due to a bug in previous ADB
130
- * versions, CLOSE(0, remote-id, "") was also used for normal
131
- * CLOSE() operations.
132
- */
133
-
134
- // So don't return if `reject` didn't find a pending socket
135
- if (packet.arg0 === 0 &&
136
- this.initializers.reject(packet.arg1, new Error('Socket open failed'))) {
137
- // Device failed to create the socket
138
- return;
139
- }
140
-
141
- const socket = this.sockets.get(packet.arg1);
142
- if (socket) {
143
- // The device want to close the socket
144
- if (!socket.closed) {
145
- await this.sendPacket(AdbCommand.Close, packet.arg1, packet.arg0);
146
- }
147
- socket.dispose();
148
- this.sockets.delete(packet.arg1);
149
- return;
150
- }
151
-
152
- // Maybe the device is responding to a packet of last connection
153
- // Just ignore it
154
- }
155
-
156
- private async handleOpen(packet: AdbPacket) {
157
- // AsyncOperationManager doesn't support get and skip an ID
158
- // Use `add` + `resolve` to simulate this behavior
159
- const [localId] = this.initializers.add<number>();
160
- this.initializers.resolve(localId, undefined);
161
-
162
- const remoteId = packet.arg0;
163
- const serviceString = this.backend.decodeUtf8(packet.payload!);
164
-
165
- const controller = new AdbSocketController({
166
- dispatcher: this,
167
- localId,
168
- remoteId,
169
- localCreated: false,
170
- serviceString,
171
- });
172
- const socket = new AdbSocket(controller);
173
-
174
- const args: AdbIncomingSocketEventArgs = {
175
- handled: false,
176
- packet,
177
- serviceString,
178
- socket,
179
- };
180
- this.incomingSocketEvent.fire(args);
181
-
182
- if (args.handled) {
183
- this.sockets.set(localId, controller);
184
- await this.sendPacket(AdbCommand.OK, localId, remoteId);
185
- } else {
186
- await this.sendPacket(AdbCommand.Close, 0, remoteId);
187
- }
188
- }
189
-
190
- public start() {
191
- this._running = true;
192
- this.receiveLoop();
193
- }
194
-
195
- public async createSocket(serviceString: string): Promise<AdbSocket> {
196
- if (this.appendNullToServiceString) {
197
- serviceString += '\0';
198
- }
199
-
200
- const [localId, initializer] = this.initializers.add<number>();
201
- await this.sendPacket(AdbCommand.Open, localId, 0, serviceString);
202
-
203
- const remoteId = await initializer;
204
- const controller = new AdbSocketController({
205
- dispatcher: this,
206
- localId,
207
- remoteId,
208
- localCreated: true,
209
- serviceString,
210
- });
211
- this.sockets.set(controller.localId, controller);
212
-
213
- return new AdbSocket(controller);
214
- }
215
-
216
- public sendPacket(packet: AdbPacketInit): Promise<void>;
217
- public sendPacket(
218
- command: AdbCommand,
219
- arg0: number,
220
- arg1: number,
221
- payload?: string | ArrayBuffer
222
- ): Promise<void>;
223
- public async sendPacket(
224
- packetOrCommand: AdbPacketInit | AdbCommand,
225
- arg0?: number,
226
- arg1?: number,
227
- payload: string | ArrayBuffer = EmptyArrayBuffer,
228
- ): Promise<void> {
229
- let init: AdbPacketInit;
230
- if (arg0 === undefined) {
231
- init = packetOrCommand as AdbPacketInit;
232
- } else {
233
- init = {
234
- command: packetOrCommand as AdbCommand,
235
- arg0: arg0 as number,
236
- arg1: arg1 as number,
237
- payload: typeof payload === 'string' ? this.backend.encodeUtf8(payload) : payload,
238
- };
239
- }
240
-
241
- if (init.payload &&
242
- init.payload.byteLength > this.maxPayloadSize) {
243
- throw new Error('payload too large');
244
- }
245
-
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();
256
- }
257
- }
258
-
259
- public dispose() {
260
- this._running = false;
261
-
262
- for (const socket of this.sockets.values()) {
263
- socket.dispose();
264
- }
265
- this.sockets.clear();
266
-
267
- super.dispose();
268
- }
269
- }
1
+ import { AsyncOperationManager } from '@yume-chan/async';
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
+ }
15
+
16
+ export interface AdbIncomingSocketEventArgs {
17
+ handled: boolean;
18
+
19
+ packet: AdbPacket;
20
+
21
+ serviceString: string;
22
+
23
+ socket: AdbSocket;
24
+ }
25
+
26
+ const EmptyArrayBuffer = new ArrayBuffer(0);
27
+
28
+ export class AdbPacketDispatcher extends AutoDisposable {
29
+ // ADB socket id starts from 1
30
+ // (0 means open failed)
31
+ 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;
35
+
36
+ public readonly backend: AdbBackend;
37
+
38
+ public maxPayloadSize = 0;
39
+ public calculateChecksum = true;
40
+ public appendNullToServiceString = true;
41
+
42
+ private readonly packetEvent = this.addDisposable(new EventEmitter<AdbPacketReceivedEventArgs>());
43
+ public get onPacket() { return this.packetEvent.event; }
44
+
45
+ private readonly incomingSocketEvent = this.addDisposable(new EventEmitter<AdbIncomingSocketEventArgs>());
46
+ public get onIncomingSocket() { return this.incomingSocketEvent.event; }
47
+
48
+ private readonly errorEvent = this.addDisposable(new EventEmitter<Error>());
49
+ public get onError() { return this.errorEvent.event; }
50
+
51
+ private _running = false;
52
+ public get running() { return this._running; }
53
+
54
+ public constructor(backend: AdbBackend, logger?: AdbLogger) {
55
+ super();
56
+
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);
78
+ }
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
+ }
106
+ }
107
+
108
+ private handleOk(packet: AdbPacket) {
109
+ if (this.initializers.resolve(packet.arg1, packet.arg0)) {
110
+ // Device successfully created the socket
111
+ return;
112
+ }
113
+
114
+ const socket = this.sockets.get(packet.arg1);
115
+ if (socket) {
116
+ // Device has received last `WRTE` to the socket
117
+ socket.ack();
118
+ return;
119
+ }
120
+
121
+ // Maybe the device is responding to a packet of last connection
122
+ // Tell the device to close the socket
123
+ this.sendPacket(AdbCommand.Close, packet.arg1, packet.arg0);
124
+ }
125
+
126
+ private async handleClose(packet: AdbPacket) {
127
+ // From https://android.googlesource.com/platform/packages/modules/adb/+/65d18e2c1cc48b585811954892311b28a4c3d188/adb.cpp#459
128
+ /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
129
+ * a failed OPEN only. However, due to a bug in previous ADB
130
+ * versions, CLOSE(0, remote-id, "") was also used for normal
131
+ * CLOSE() operations.
132
+ */
133
+
134
+ // So don't return if `reject` didn't find a pending socket
135
+ if (packet.arg0 === 0 &&
136
+ this.initializers.reject(packet.arg1, new Error('Socket open failed'))) {
137
+ // Device failed to create the socket
138
+ return;
139
+ }
140
+
141
+ const socket = this.sockets.get(packet.arg1);
142
+ if (socket) {
143
+ // The device want to close the socket
144
+ if (!socket.closed) {
145
+ await this.sendPacket(AdbCommand.Close, packet.arg1, packet.arg0);
146
+ }
147
+ socket.dispose();
148
+ this.sockets.delete(packet.arg1);
149
+ return;
150
+ }
151
+
152
+ // Maybe the device is responding to a packet of last connection
153
+ // Just ignore it
154
+ }
155
+
156
+ private async handleOpen(packet: AdbPacket) {
157
+ // AsyncOperationManager doesn't support get and skip an ID
158
+ // Use `add` + `resolve` to simulate this behavior
159
+ const [localId] = this.initializers.add<number>();
160
+ this.initializers.resolve(localId, undefined);
161
+
162
+ const remoteId = packet.arg0;
163
+ const serviceString = decodeUtf8(packet.payload!);
164
+
165
+ const controller = new AdbSocketController({
166
+ dispatcher: this,
167
+ localId,
168
+ remoteId,
169
+ localCreated: false,
170
+ serviceString,
171
+ });
172
+ const socket = new AdbSocket(controller);
173
+
174
+ const args: AdbIncomingSocketEventArgs = {
175
+ handled: false,
176
+ packet,
177
+ serviceString,
178
+ socket,
179
+ };
180
+ this.incomingSocketEvent.fire(args);
181
+
182
+ if (args.handled) {
183
+ this.sockets.set(localId, controller);
184
+ await this.sendPacket(AdbCommand.OK, localId, remoteId);
185
+ } else {
186
+ await this.sendPacket(AdbCommand.Close, 0, remoteId);
187
+ }
188
+ }
189
+
190
+ public start() {
191
+ this._running = true;
192
+ this.receiveLoop();
193
+ }
194
+
195
+ public async createSocket(serviceString: string): Promise<AdbSocket> {
196
+ if (this.appendNullToServiceString) {
197
+ serviceString += '\0';
198
+ }
199
+
200
+ const [localId, initializer] = this.initializers.add<number>();
201
+ await this.sendPacket(AdbCommand.Open, localId, 0, serviceString);
202
+
203
+ const remoteId = await initializer;
204
+ const controller = new AdbSocketController({
205
+ dispatcher: this,
206
+ localId,
207
+ remoteId,
208
+ localCreated: true,
209
+ serviceString,
210
+ });
211
+ this.sockets.set(controller.localId, controller);
212
+
213
+ return new AdbSocket(controller);
214
+ }
215
+
216
+ public sendPacket(packet: AdbPacketInit): Promise<void>;
217
+ public sendPacket(
218
+ command: AdbCommand,
219
+ arg0: number,
220
+ arg1: number,
221
+ payload?: string | ArrayBuffer
222
+ ): Promise<void>;
223
+ public async sendPacket(
224
+ packetOrCommand: AdbPacketInit | AdbCommand,
225
+ arg0?: number,
226
+ arg1?: number,
227
+ payload: string | ArrayBuffer = EmptyArrayBuffer,
228
+ ): Promise<void> {
229
+ let init: AdbPacketInit;
230
+ if (arg0 === undefined) {
231
+ init = packetOrCommand as AdbPacketInit;
232
+ } else {
233
+ init = {
234
+ command: packetOrCommand as AdbCommand,
235
+ arg0: arg0 as number,
236
+ arg1: arg1 as number,
237
+ payload: typeof payload === 'string' ? encodeUtf8(payload) : payload,
238
+ };
239
+ }
240
+
241
+ if (init.payload &&
242
+ init.payload.byteLength > this.maxPayloadSize) {
243
+ throw new Error('payload too large');
244
+ }
245
+
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();
256
+ }
257
+ }
258
+
259
+ public override dispose() {
260
+ this._running = false;
261
+
262
+ for (const socket of this.sockets.values()) {
263
+ socket.dispose();
264
+ }
265
+ this.sockets.clear();
266
+
267
+ super.dispose();
268
+ }
269
+ }
@@ -1,6 +1,6 @@
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 './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,12 +1,12 @@
1
- import { AdbPacket, AdbPacketInit } from '../packet';
2
- import { AdbSocket } from './socket';
3
-
4
- export interface AdbLogger {
5
- onIncomingPacket?(packet: AdbPacket): void;
6
-
7
- onOutgoingPacket?(packet: AdbPacketInit): void;
8
-
9
- onSocketOpened?(socket: AdbSocket): void;
10
-
11
- onSocketClosed?(socket: AdbSocket): void;
12
- }
1
+ import { AdbPacket, AdbPacketInit } from '../packet';
2
+ import { AdbSocket } from './socket';
3
+
4
+ export interface AdbLogger {
5
+ onIncomingPacket?(packet: AdbPacket): void;
6
+
7
+ onOutgoingPacket?(packet: AdbPacketInit): void;
8
+
9
+ onSocketOpened?(socket: AdbSocket): void;
10
+
11
+ onSocketClosed?(socket: AdbSocket): void;
12
+ }
@@ -1,28 +1,28 @@
1
- import { AdbSocketController, AdbSocketInfo } from './controller';
2
-
3
- export class AdbSocket implements AdbSocketInfo {
4
- private readonly controller: AdbSocketController;
5
-
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; }
11
-
12
- public get closed() { return this.controller.closed; }
13
-
14
- public get onData() { return this.controller.dataEvent.event; }
15
- public get onClose() { return this.controller.onClose; }
16
-
17
- public constructor(controller: AdbSocketController) {
18
- this.controller = controller;
19
- }
20
-
21
- public write(data: ArrayBuffer): Promise<void> {
22
- return this.controller.write(data);
23
- }
24
-
25
- public close(): Promise<void> {
26
- return this.controller.close();
27
- }
28
- }
1
+ import { AdbSocketController, AdbSocketInfo } from './controller';
2
+
3
+ export class AdbSocket implements AdbSocketInfo {
4
+ private readonly controller: AdbSocketController;
5
+
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; }
11
+
12
+ public get closed() { return this.controller.closed; }
13
+
14
+ public get onData() { return this.controller.dataEvent.event; }
15
+ public get onClose() { return this.controller.onClose; }
16
+
17
+ public constructor(controller: AdbSocketController) {
18
+ this.controller = controller;
19
+ }
20
+
21
+ public write(data: ArrayBuffer): Promise<void> {
22
+ return this.controller.write(data);
23
+ }
24
+
25
+ public close(): Promise<void> {
26
+ return this.controller.close();
27
+ }
28
+ }