@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,133 +1,134 @@
1
- import { AutoDisposable } from '@yume-chan/event';
2
- import Struct from '@yume-chan/struct';
3
- import { AdbPacket } from '../packet';
4
- import { AdbIncomingSocketEventArgs, AdbPacketDispatcher, AdbSocket } from '../socket';
5
- import { AdbBufferedStream } from '../stream';
6
-
7
- export interface AdbReverseHandler {
8
- onSocket(packet: AdbPacket, socket: AdbSocket): void;
9
- }
10
-
11
- export interface AdbForwardListener {
12
- deviceSerial: string;
13
-
14
- localName: string;
15
-
16
- remoteName: string;
17
- }
18
-
19
- const AdbReverseStringResponse =
20
- new Struct({ littleEndian: true })
21
- .string('length', { length: 4 })
22
- .string('content', { lengthField: 'length', lengthFieldBase: 16 });
23
-
24
- const AdbReverseErrorResponse =
25
- new Struct({ littleEndian: true })
26
- .fields(AdbReverseStringResponse)
27
- .postDeserialize((value) => {
28
- throw new Error(value.content);
29
- });
30
-
31
- export class AdbReverseCommand extends AutoDisposable {
32
- protected localPortToHandler = new Map<number, AdbReverseHandler>();
33
-
34
- protected deviceAddressToLocalPort = new Map<string, number>();
35
-
36
- protected dispatcher: AdbPacketDispatcher;
37
-
38
- protected listening = false;
39
-
40
- public constructor(dispatcher: AdbPacketDispatcher) {
41
- super();
42
-
43
- this.dispatcher = dispatcher;
44
- this.addDisposable(this.dispatcher.onIncomingSocket(this.handleIncomingSocket, this));
45
- }
46
-
47
- protected handleIncomingSocket(e: AdbIncomingSocketEventArgs): void {
48
- if (e.handled) {
49
- return;
50
- }
51
-
52
- const address = this.dispatcher.backend.decodeUtf8(e.packet.payload!);
53
- // tcp:1234\0
54
- const port = Number.parseInt(address.substring(4));
55
- if (this.localPortToHandler.has(port)) {
56
- this.localPortToHandler.get(port)!.onSocket(e.packet, e.socket);
57
- e.handled = true;
58
- }
59
- }
60
-
61
- private async createBufferedStream(service: string) {
62
- const socket = await this.dispatcher.createSocket(service);
63
- return new AdbBufferedStream(socket);
64
- }
65
-
66
- private async sendRequest(service: string) {
67
- const stream = await this.createBufferedStream(service);
68
- const success = this.dispatcher.backend.decodeUtf8(await stream.read(4)) === 'OKAY';
69
- if (!success) {
70
- await AdbReverseErrorResponse.deserialize(stream);
71
- }
72
- return stream;
73
- }
74
-
75
- public async list(): Promise<AdbForwardListener[]> {
76
- const stream = await this.createBufferedStream('reverse:list-forward');
77
-
78
- const response = await AdbReverseStringResponse.deserialize(stream);
79
- return response.content!.split('\n').map(line => {
80
- const [deviceSerial, localName, remoteName] = line.split(' ');
81
- return { deviceSerial, localName, remoteName };
82
- });
83
-
84
- // No need to close the stream, device will close it
85
- }
86
-
87
- /**
88
- * @param deviceAddress The address adbd on device is listening on. Can be `tcp:0` to let adbd choose an available TCP port by itself.
89
- * @param localPort Native ADB will open a connection to localPort when reverse connection starts. In webadb, it's only used to uniquely identify a reverse registry, `handler` will be called on connection.
90
- * @param handler A callback to handle incoming connections
91
- * @returns If `deviceAddress` is `tcp:0`, return `tcp:{ACTUAL_LISTENING_PORT}`; otherwise, return `deviceAddress`.
92
- */
93
- public async add(
94
- deviceAddress: string,
95
- localPort: number,
96
- handler: AdbReverseHandler,
97
- ): Promise<string> {
98
- const stream = await this.sendRequest(`reverse:forward:${deviceAddress};tcp:${localPort}`);
99
-
100
- // `tcp:0` tells the device to pick an available port.
101
- // However, device will response with the selected port for all `tcp:` requests.
102
- if (deviceAddress.startsWith('tcp:')) {
103
- const response = await AdbReverseStringResponse.deserialize(stream);
104
- deviceAddress = `tcp:${Number.parseInt(response.content!, 10)}`;
105
- }
106
-
107
- this.localPortToHandler.set(localPort, handler);
108
- this.deviceAddressToLocalPort.set(deviceAddress, localPort);
109
- return deviceAddress;
110
-
111
- // No need to close the stream, device will close it
112
- }
113
-
114
- public async remove(deviceAddress: string): Promise<void> {
115
- await this.sendRequest(`reverse:killforward:${deviceAddress}`);
116
-
117
- if (this.deviceAddressToLocalPort.has(deviceAddress)) {
118
- this.localPortToHandler.delete(this.deviceAddressToLocalPort.get(deviceAddress)!);
119
- this.deviceAddressToLocalPort.delete(deviceAddress);
120
- }
121
-
122
- // No need to close the stream, device will close it
123
- }
124
-
125
- public async removeAll(): Promise<void> {
126
- await this.sendRequest(`reverse:killforward-all`);
127
-
128
- this.deviceAddressToLocalPort.clear();
129
- this.localPortToHandler.clear();
130
-
131
- // No need to close the stream, device will close it
132
- }
133
- }
1
+ import { AutoDisposable } from '@yume-chan/event';
2
+ import Struct from '@yume-chan/struct';
3
+ import type { AdbPacket } from '../packet';
4
+ import type { AdbIncomingSocketEventArgs, AdbPacketDispatcher, AdbSocket } from '../socket';
5
+ import { AdbBufferedStream } from '../stream';
6
+ import { decodeUtf8 } from "../utils";
7
+
8
+ export interface AdbReverseHandler {
9
+ onSocket(packet: AdbPacket, socket: AdbSocket): void;
10
+ }
11
+
12
+ export interface AdbForwardListener {
13
+ deviceSerial: string;
14
+
15
+ localName: string;
16
+
17
+ remoteName: string;
18
+ }
19
+
20
+ const AdbReverseStringResponse =
21
+ new Struct({ littleEndian: true })
22
+ .string('length', { length: 4 })
23
+ .string('content', { lengthField: 'length', lengthFieldBase: 16 });
24
+
25
+ const AdbReverseErrorResponse =
26
+ new Struct({ littleEndian: true })
27
+ .fields(AdbReverseStringResponse)
28
+ .postDeserialize((value) => {
29
+ throw new Error(value.content);
30
+ });
31
+
32
+ export class AdbReverseCommand extends AutoDisposable {
33
+ protected localPortToHandler = new Map<number, AdbReverseHandler>();
34
+
35
+ protected deviceAddressToLocalPort = new Map<string, number>();
36
+
37
+ protected dispatcher: AdbPacketDispatcher;
38
+
39
+ protected listening = false;
40
+
41
+ public constructor(dispatcher: AdbPacketDispatcher) {
42
+ super();
43
+
44
+ this.dispatcher = dispatcher;
45
+ this.addDisposable(this.dispatcher.onIncomingSocket(this.handleIncomingSocket, this));
46
+ }
47
+
48
+ protected handleIncomingSocket(e: AdbIncomingSocketEventArgs): void {
49
+ if (e.handled) {
50
+ return;
51
+ }
52
+
53
+ const address = decodeUtf8(e.packet.payload!);
54
+ // tcp:1234\0
55
+ const port = Number.parseInt(address.substring(4));
56
+ if (this.localPortToHandler.has(port)) {
57
+ this.localPortToHandler.get(port)!.onSocket(e.packet, e.socket);
58
+ e.handled = true;
59
+ }
60
+ }
61
+
62
+ private async createBufferedStream(service: string) {
63
+ const socket = await this.dispatcher.createSocket(service);
64
+ return new AdbBufferedStream(socket);
65
+ }
66
+
67
+ private async sendRequest(service: string) {
68
+ const stream = await this.createBufferedStream(service);
69
+ const success = decodeUtf8(await stream.read(4)) === 'OKAY';
70
+ if (!success) {
71
+ await AdbReverseErrorResponse.deserialize(stream);
72
+ }
73
+ return stream;
74
+ }
75
+
76
+ public async list(): Promise<AdbForwardListener[]> {
77
+ const stream = await this.createBufferedStream('reverse:list-forward');
78
+
79
+ const response = await AdbReverseStringResponse.deserialize(stream);
80
+ return response.content!.split('\n').map(line => {
81
+ const [deviceSerial, localName, remoteName] = line.split(' ');
82
+ return { deviceSerial, localName, remoteName };
83
+ });
84
+
85
+ // No need to close the stream, device will close it
86
+ }
87
+
88
+ /**
89
+ * @param deviceAddress The address adbd on device is listening on. Can be `tcp:0` to let adbd choose an available TCP port by itself.
90
+ * @param localPort Native ADB will open a connection to localPort when reverse connection starts. In webadb, it's only used to uniquely identify a reverse registry, `handler` will be called on connection.
91
+ * @param handler A callback to handle incoming connections
92
+ * @returns If `deviceAddress` is `tcp:0`, return `tcp:{ACTUAL_LISTENING_PORT}`; otherwise, return `deviceAddress`.
93
+ */
94
+ public async add(
95
+ deviceAddress: string,
96
+ localPort: number,
97
+ handler: AdbReverseHandler,
98
+ ): Promise<string> {
99
+ const stream = await this.sendRequest(`reverse:forward:${deviceAddress};tcp:${localPort}`);
100
+
101
+ // `tcp:0` tells the device to pick an available port.
102
+ // However, device will response with the selected port for all `tcp:` requests.
103
+ if (deviceAddress.startsWith('tcp:')) {
104
+ const response = await AdbReverseStringResponse.deserialize(stream);
105
+ deviceAddress = `tcp:${Number.parseInt(response.content!, 10)}`;
106
+ }
107
+
108
+ this.localPortToHandler.set(localPort, handler);
109
+ this.deviceAddressToLocalPort.set(deviceAddress, localPort);
110
+ return deviceAddress;
111
+
112
+ // No need to close the stream, device will close it
113
+ }
114
+
115
+ public async remove(deviceAddress: string): Promise<void> {
116
+ await this.sendRequest(`reverse:killforward:${deviceAddress}`);
117
+
118
+ if (this.deviceAddressToLocalPort.has(deviceAddress)) {
119
+ this.localPortToHandler.delete(this.deviceAddressToLocalPort.get(deviceAddress)!);
120
+ this.deviceAddressToLocalPort.delete(deviceAddress);
121
+ }
122
+
123
+ // No need to close the stream, device will close it
124
+ }
125
+
126
+ public async removeAll(): Promise<void> {
127
+ await this.sendRequest(`reverse:killforward-all`);
128
+
129
+ this.deviceAddressToLocalPort.clear();
130
+ this.localPortToHandler.clear();
131
+
132
+ // No need to close the stream, device will close it
133
+ }
134
+ }
@@ -1,68 +1,87 @@
1
- import { Adb } from '../../adb';
2
- import { AdbFeatures } from '../../features';
3
- import { AdbLegacyShell } from './legacy';
4
- import { AdbShellProtocol } from './protocol';
5
- import { AdbShell } from './types';
6
-
7
- export * from './legacy';
8
- export * from './protocol';
9
- export * from './types';
10
- export * from './utils';
11
-
12
- export type AdbShellProtocolOption = 'auto' | 'enable' | 'disable';
13
-
14
- export interface AdbChildProcessOptions {
15
- shellProtocol: 'auto' | 'enable' | 'disable',
16
- }
17
-
18
- const DefaultOptions: AdbChildProcessOptions = {
19
- shellProtocol: 'auto',
20
- };
21
-
22
- export class AdbChildProcess {
23
- public readonly adb: Adb;
24
-
25
- public get supportsShellProtocol(): boolean {
26
- return this.adb.features!.includes(AdbFeatures.ShellV2);
27
- }
28
-
29
- public constructor(adb: Adb) {
30
- this.adb = adb;
31
- }
32
-
33
- private async createShell(command: string, options?: Partial<AdbChildProcessOptions>): Promise<AdbShell> {
34
- let { shellProtocol } = { ...DefaultOptions, ...options };
35
- switch (shellProtocol) {
36
- case 'auto':
37
- shellProtocol = this.supportsShellProtocol ? 'enable' : 'disable';
38
- break;
39
- case 'enable':
40
- if (!shellProtocol) {
41
- throw new Error('`shellProtocol` has been set to `enable` but the device does not support it');
42
- }
43
- break;
44
- }
45
-
46
- if (shellProtocol === 'enable') {
47
- return new AdbShellProtocol(await this.adb.createSocket(`shell,v2,pty:${command}`));
48
- }
49
-
50
- return new AdbLegacyShell(await this.adb.createSocket(`shell:${command}`));
51
- }
52
-
53
- public shell(options?: Partial<AdbChildProcessOptions>): Promise<AdbShell> {
54
- return this.createShell('', options);
55
- }
56
-
57
- public spawn(command: string | string[], options?: Partial<AdbChildProcessOptions>): Promise<AdbShell> {
58
- if (Array.isArray(command)) {
59
- command = command.join(' ');
60
- }
61
- return this.createShell(command, options);
62
- }
63
-
64
- public exec(command: string, ...args: string[]): Promise<string> {
65
- // `exec` only need all output, using Shell Protocol only makes it more complicate.
66
- return this.adb.createSocketAndReadAll(`shell:${command} ${args.join(' ')}`);
67
- }
68
- }
1
+ import type { Adb } from '../../adb';
2
+ import { AdbLegacyShell } from './legacy';
3
+ import { AdbShellProtocol } from './protocol';
4
+ import type { AdbShell, AdbShellConstructor } from './types';
5
+
6
+ export * from './legacy';
7
+ export * from './protocol';
8
+ export * from './types';
9
+ export * from './utils';
10
+
11
+ export interface AdbChildProcessOptions {
12
+ /**
13
+ * A list of `AdbShellConstructor`s to be used.
14
+ *
15
+ * Different `AdbShell` has different capabilities, thus requires specific adaptations.
16
+ * Check each `AdbShell`'s documentation for details.
17
+ *
18
+ * The first one whose `isSupported` returns `true` will be used.
19
+ * If no `AdbShell` is supported, an error will be thrown.
20
+ *
21
+ * The default value is `[AdbShellProtocol, AdbLegacyShell]`.
22
+ */
23
+ shells: AdbShellConstructor[];
24
+ }
25
+
26
+ const DefaultOptions: AdbChildProcessOptions = {
27
+ shells: [AdbShellProtocol, AdbLegacyShell],
28
+ };
29
+
30
+ export class AdbChildProcess {
31
+ public readonly adb: Adb;
32
+
33
+ public constructor(adb: Adb) {
34
+ this.adb = adb;
35
+ }
36
+
37
+ private async createShell(command: string, options?: Partial<AdbChildProcessOptions>): Promise<AdbShell> {
38
+ let { shells } = { ...DefaultOptions, ...options };
39
+
40
+ let shell: AdbShellConstructor | undefined;
41
+ for (const item of shells) {
42
+ if (await item.isSupported(this.adb)) {
43
+ shell = item;
44
+ break;
45
+ }
46
+ }
47
+
48
+ if (!shell) {
49
+ throw new Error('No specified shell is supported by the device');
50
+ }
51
+
52
+ return await shell.spawn(this.adb, command);
53
+ }
54
+
55
+ /**
56
+ * Spawns the default shell in interactive mode.
57
+ * @param options The options for creating the `AdbShell`
58
+ * @returns A new `AdbShell` instance connecting to the spawned shell process.
59
+ */
60
+ public shell(options?: Partial<AdbChildProcessOptions>): Promise<AdbShell> {
61
+ return this.createShell('', options);
62
+ }
63
+
64
+ /**
65
+ * Spawns a new process using the given `command`.
66
+ * @param command The command to run, or an array of strings containing both command and args.
67
+ * @param options The options for creating the `AdbShell`
68
+ * @returns A new `AdbShell` instance connecting to the spawned process.
69
+ */
70
+ public spawn(command: string | string[], options?: Partial<AdbChildProcessOptions>): Promise<AdbShell> {
71
+ if (Array.isArray(command)) {
72
+ command = command.join(' ');
73
+ }
74
+ return this.createShell(command, options);
75
+ }
76
+
77
+ /**
78
+ * Spawns a new process, waits until it exits, and returns the entire output.
79
+ * @param command The command to run
80
+ * @param args List of command arguments
81
+ * @returns The entire output of the command
82
+ */
83
+ public exec(command: string, ...args: string[]): Promise<string> {
84
+ // `exec` only needs the entire output, use Legacy Shell is simpler.
85
+ return this.adb.createSocketAndReadAll(`shell:${command} ${args.join(' ')}`);
86
+ }
87
+ }
@@ -1,42 +1,59 @@
1
- import { EventEmitter } from "@yume-chan/event";
2
- import { AdbSocket } from "../../socket";
3
- import { AdbShell } from "./types";
4
-
5
- export class AdbLegacyShell implements AdbShell {
6
- private readonly socket: AdbSocket;
7
-
8
- private readonly stdoutEvent = new EventEmitter<ArrayBuffer>();
9
- public get onStdout() { return this.stdoutEvent.event; }
10
-
11
- private readonly stderrEvent = new EventEmitter<ArrayBuffer>();
12
- public get onStderr() { return this.stderrEvent.event; }
13
-
14
- private readonly exitEvent = new EventEmitter<number>();
15
- public get onExit() { return this.exitEvent.event; }
16
-
17
- public constructor(socket: AdbSocket) {
18
- this.socket = socket;
19
- this.socket.onData(this.handleData, this);
20
- this.socket.onClose(this.handleExit, this);
21
- }
22
-
23
- private handleData(data: ArrayBuffer) {
24
- this.stdoutEvent.fire(data);
25
- }
26
-
27
- private handleExit() {
28
- this.exitEvent.fire(0);
29
- }
30
-
31
- public async write(data: ArrayBuffer) {
32
- this.socket.write(data);
33
- }
34
-
35
- public resize() {
36
- // Not supported
37
- }
38
-
39
- public kill() {
40
- return this.socket.close();
41
- }
42
- }
1
+ import { EventEmitter } from "@yume-chan/event";
2
+ import type { Adb } from "../../adb";
3
+ import type { AdbSocket } from "../../socket";
4
+ import type { AdbShell } from "./types";
5
+
6
+ /**
7
+ * The legacy shell
8
+ *
9
+ * Features:
10
+ * * `onStderr`: No
11
+ * * `onExit` exit code: No
12
+ * * `resize`: No
13
+ */
14
+ export class AdbLegacyShell implements AdbShell {
15
+ public static isSupported() { return true; }
16
+
17
+ public static async spawn(adb: Adb, command: string) {
18
+ return new AdbLegacyShell(await adb.createSocket(`shell:${command}`));
19
+ }
20
+
21
+ private readonly socket: AdbSocket;
22
+
23
+ private readonly stdoutEvent = new EventEmitter<ArrayBuffer>();
24
+ public get onStdout() { return this.stdoutEvent.event; }
25
+
26
+ private readonly stderrEvent = new EventEmitter<ArrayBuffer>();
27
+ public get onStderr() { return this.stderrEvent.event; }
28
+
29
+ private readonly exitEvent = new EventEmitter<number>();
30
+ public get onExit() { return this.exitEvent.event; }
31
+
32
+ public constructor(socket: AdbSocket) {
33
+ this.socket = socket;
34
+ this.socket.onData(this.handleData, this);
35
+ this.socket.onClose(this.handleExit, this);
36
+ }
37
+
38
+ private handleData(data: ArrayBuffer) {
39
+ // Legacy shell doesn't support splitting output streams.
40
+ this.stdoutEvent.fire(data);
41
+ }
42
+
43
+ private handleExit() {
44
+ // Legacy shell doesn't support returning exit code.
45
+ this.exitEvent.fire(0);
46
+ }
47
+
48
+ public async write(data: ArrayBuffer) {
49
+ this.socket.write(data);
50
+ }
51
+
52
+ public resize() {
53
+ // Not supported
54
+ }
55
+
56
+ public kill() {
57
+ return this.socket.close();
58
+ }
59
+ }