@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
package/src/packet.ts CHANGED
@@ -1,89 +1,84 @@
1
- import Struct from '@yume-chan/struct';
2
- import { AdbBackend } from './backend';
3
- import { BufferedStream } from './stream';
4
-
5
- export enum AdbCommand {
6
- Auth = 0x48545541, // 'AUTH'
7
- Close = 0x45534c43, // 'CLSE'
8
- Connect = 0x4e584e43, // 'CNXN'
9
- OK = 0x59414b4f, // 'OKAY'
10
- Open = 0x4e45504f, // 'OPEN'
11
- Write = 0x45545257, // 'WRTE'
12
- }
13
-
14
- const AdbPacketHeader =
15
- new Struct({ littleEndian: true })
16
- .uint32('command')
17
- .uint32('arg0')
18
- .uint32('arg1')
19
- .uint32('payloadLength')
20
- .uint32('checksum')
21
- .int32('magic');
22
-
23
- const AdbPacketStruct =
24
- new Struct({ littleEndian: true })
25
- .fields(AdbPacketHeader)
26
- .arrayBuffer('payload', { lengthField: 'payloadLength' });
27
-
28
- export type AdbPacket = typeof AdbPacketStruct['TDeserializeResult'];
29
-
30
- export type AdbPacketInit = Omit<typeof AdbPacketStruct['TInit'], 'checksum' | 'magic'>;
31
-
32
- export namespace AdbPacket {
33
- export async function read(backend: AdbBackend): Promise<AdbPacket> {
34
- let buffer = await backend.read(24);
35
-
36
- // Detect boundary
37
- // Note that it relies on the backend to only return data from one write operation
38
- while (buffer.byteLength !== 24) {
39
- // Maybe it's a payload from last connection.
40
- // Ignore and try again
41
- buffer = await backend.read(24);
42
- }
43
-
44
- let bufferUsed = false;
45
- const stream = new BufferedStream({
46
- read(length: number) {
47
- if (!bufferUsed) {
48
- bufferUsed = true;
49
- return buffer;
50
- }
51
- return backend.read(length);
52
- }
53
- });
54
-
55
- return AdbPacketStruct.deserialize({
56
- read: stream.read.bind(stream),
57
- decodeUtf8: backend.decodeUtf8.bind(backend),
58
- encodeUtf8: backend.encodeUtf8.bind(backend),
59
- });
60
- }
61
-
62
- export async function write(
63
- init: AdbPacketInit,
64
- calculateChecksum: boolean,
65
- backend: AdbBackend
66
- ): Promise<void> {
67
- let checksum: number;
68
- if (calculateChecksum && init.payload) {
69
- const array = new Uint8Array(init.payload);
70
- checksum = array.reduce((result, item) => result + item, 0);
71
- } else {
72
- checksum = 0;
73
- }
74
-
75
- const packet = {
76
- ...init,
77
- checksum,
78
- magic: init.command ^ 0xFFFFFFFF,
79
- payloadLength: init.payload.byteLength,
80
- };
81
-
82
- // Write payload separately to avoid an extra copy
83
- const header = AdbPacketHeader.serialize(packet, backend);
84
- await backend.write(header);
85
- if (packet.payload.byteLength) {
86
- await backend.write(packet.payload);
87
- }
88
- }
89
- }
1
+ import Struct from '@yume-chan/struct';
2
+ import { AdbBackend } from './backend';
3
+ import { BufferedStream } from './stream';
4
+
5
+ export enum AdbCommand {
6
+ Auth = 0x48545541, // 'AUTH'
7
+ Close = 0x45534c43, // 'CLSE'
8
+ Connect = 0x4e584e43, // 'CNXN'
9
+ OK = 0x59414b4f, // 'OKAY'
10
+ Open = 0x4e45504f, // 'OPEN'
11
+ Write = 0x45545257, // 'WRTE'
12
+ }
13
+
14
+ const AdbPacketHeader =
15
+ new Struct({ littleEndian: true })
16
+ .uint32('command')
17
+ .uint32('arg0')
18
+ .uint32('arg1')
19
+ .uint32('payloadLength')
20
+ .uint32('checksum')
21
+ .int32('magic');
22
+
23
+ const AdbPacketStruct =
24
+ new Struct({ littleEndian: true })
25
+ .fields(AdbPacketHeader)
26
+ .arrayBuffer('payload', { lengthField: 'payloadLength' });
27
+
28
+ export type AdbPacket = typeof AdbPacketStruct['TDeserializeResult'];
29
+
30
+ export type AdbPacketInit = Omit<typeof AdbPacketStruct['TInit'], 'checksum' | 'magic'>;
31
+
32
+ export namespace AdbPacket {
33
+ export async function read(backend: AdbBackend): Promise<AdbPacket> {
34
+ // Detect boundary
35
+ // Note that it relies on the backend to only return data from one write operation
36
+ let buffer: ArrayBuffer;
37
+ do {
38
+ // Maybe it's a payload from last connection.
39
+ // Ignore and try again
40
+ buffer = await backend.read(24);
41
+ } while (buffer.byteLength !== 24);
42
+
43
+ let bufferUsed = false;
44
+ const stream = new BufferedStream({
45
+ async read(length: number) {
46
+ if (!bufferUsed) {
47
+ bufferUsed = true;
48
+ return buffer;
49
+ }
50
+ return backend.read(length);
51
+ }
52
+ });
53
+
54
+ return AdbPacketStruct.deserialize(stream);
55
+ }
56
+
57
+ export async function write(
58
+ init: AdbPacketInit,
59
+ calculateChecksum: boolean,
60
+ backend: AdbBackend
61
+ ): Promise<void> {
62
+ let checksum: number;
63
+ if (calculateChecksum && init.payload) {
64
+ const array = new Uint8Array(init.payload);
65
+ checksum = array.reduce((result, item) => result + item, 0);
66
+ } else {
67
+ checksum = 0;
68
+ }
69
+
70
+ const packet = {
71
+ ...init,
72
+ checksum,
73
+ magic: init.command ^ 0xFFFFFFFF,
74
+ payloadLength: init.payload.byteLength,
75
+ };
76
+
77
+ // Write payload separately to avoid an extra copy
78
+ const header = AdbPacketHeader.serialize(packet);
79
+ await backend.write(header);
80
+ if (packet.payload.byteLength) {
81
+ await backend.write(packet.payload);
82
+ }
83
+ }
84
+ }
@@ -1,28 +1,28 @@
1
- import { EventEmitter, EventListenerInfo, RemoveEventListener } from '@yume-chan/event';
2
-
3
- const NoopRemoveEventListener: RemoveEventListener = () => { };
4
- NoopRemoveEventListener.dispose = NoopRemoveEventListener;
5
-
6
- export class CloseEventEmitter extends EventEmitter<void, void>{
7
- private closed = false;
8
-
9
- protected addEventListener(info: EventListenerInfo<void, void>) {
10
- if (this.closed) {
11
- info.listener.apply(info.thisArg, [undefined, ...info.args]);
12
- return NoopRemoveEventListener;
13
- } else {
14
- return super.addEventListener(info);
15
- }
16
- }
17
-
18
- public fire() {
19
- super.fire();
20
- this.closed = true;
21
- this.listeners.length = 0;
22
- }
23
-
24
- public dispose() {
25
- this.fire();
26
- super.dispose();
27
- }
28
- }
1
+ import { EventEmitter, EventListenerInfo, RemoveEventListener } from '@yume-chan/event';
2
+
3
+ const NoopRemoveEventListener: RemoveEventListener = () => { };
4
+ NoopRemoveEventListener.dispose = NoopRemoveEventListener;
5
+
6
+ export class CloseEventEmitter extends EventEmitter<void, void>{
7
+ private closed = false;
8
+
9
+ protected override addEventListener(info: EventListenerInfo<void, void>) {
10
+ if (this.closed) {
11
+ info.listener.apply(info.thisArg, [undefined, ...info.args]);
12
+ return NoopRemoveEventListener;
13
+ } else {
14
+ return super.addEventListener(info);
15
+ }
16
+ }
17
+
18
+ public override fire() {
19
+ super.fire();
20
+ this.closed = true;
21
+ this.listeners.length = 0;
22
+ }
23
+
24
+ public override dispose() {
25
+ this.fire();
26
+ super.dispose();
27
+ }
28
+ }
@@ -1,105 +1,105 @@
1
- import { AutoDisposable } from '@yume-chan/event';
2
- import { AdbBackend } from '../backend';
3
- import { AdbCommand } from '../packet';
4
- import { AutoResetEvent, chunkArrayLike } from '../utils';
5
- import { CloseEventEmitter } from './close-event-emitter';
6
- import { DataEventEmitter } from './data-event-emitter';
7
- import { AdbPacketDispatcher } from './dispatcher';
8
-
9
- export interface AdbSocketInfo {
10
- backend: AdbBackend;
11
-
12
- localId: number;
13
-
14
- remoteId: number;
15
-
16
- localCreated: boolean;
17
-
18
- serviceString: string;
19
- }
20
-
21
- export interface AdbSocketConstructionOptions {
22
- dispatcher: AdbPacketDispatcher;
23
-
24
- localId: number;
25
-
26
- remoteId: number;
27
-
28
- localCreated: boolean;
29
-
30
- serviceString: string;
31
- }
32
-
33
- export class AdbSocketController extends AutoDisposable implements AdbSocketInfo {
34
- private readonly writeChunkLock = this.addDisposable(new AutoResetEvent());
35
- private readonly writeLock = this.addDisposable(new AutoResetEvent());
36
-
37
- private readonly dispatcher!: AdbPacketDispatcher;
38
- public get backend() { return this.dispatcher.backend; }
39
-
40
- public readonly localId!: number;
41
- public readonly remoteId!: number;
42
- public readonly localCreated!: boolean;
43
- public readonly serviceString!: string;
44
-
45
- public readonly dataEvent = this.addDisposable(new DataEventEmitter<ArrayBuffer>());
46
-
47
- private _closed = false;
48
- public get closed() { return this._closed; }
49
-
50
- private readonly closeEvent = this.addDisposable(new CloseEventEmitter());
51
- public get onClose() { return this.closeEvent.event; }
52
-
53
- public constructor(options: AdbSocketConstructionOptions) {
54
- super();
55
- Object.assign(this, options);
56
- }
57
-
58
- private async writeChunk(data: ArrayBuffer): Promise<void> {
59
- try {
60
- // Wait for an ack packet
61
- await this.writeChunkLock.wait();
62
- } catch {
63
- // Lock has been disposed, which means the socket has been closed
64
- throw new Error('Can not write after closed');
65
- }
66
-
67
- await this.dispatcher.sendPacket(AdbCommand.Write, this.localId, this.remoteId, data);
68
- }
69
-
70
- public async write(data: ArrayBuffer): Promise<void> {
71
- try {
72
- // Keep write operations in order
73
- await this.writeLock.wait();
74
- } catch {
75
- // Lock has been disposed, which means the socket has been closed
76
- throw new Error('Can not write after closed');
77
- }
78
-
79
- for await (const chunk of chunkArrayLike(data, this.dispatcher.maxPayloadSize)) {
80
- await this.writeChunk(chunk);
81
- }
82
- this.writeLock.notify();
83
- }
84
-
85
- public ack() {
86
- this.writeChunkLock.notify();
87
- }
88
-
89
- public async close(): Promise<void> {
90
- if (!this._closed) {
91
- // Immediately cancel all pending writes
92
- this.writeLock.dispose();
93
- this.writeChunkLock.dispose();
94
-
95
- await this.dispatcher.sendPacket(AdbCommand.Close, this.localId, this.remoteId);
96
- this._closed = true;
97
- }
98
- }
99
-
100
- public dispose() {
101
- this._closed = true;
102
- this.closeEvent.fire();
103
- super.dispose();
104
- }
105
- }
1
+ import { AutoDisposable } from '@yume-chan/event';
2
+ import { AdbBackend } from '../backend';
3
+ import { AdbCommand } from '../packet';
4
+ import { AutoResetEvent, chunkArrayLike } from '../utils';
5
+ import { CloseEventEmitter } from './close-event-emitter';
6
+ import { DataEventEmitter } from './data-event-emitter';
7
+ import { AdbPacketDispatcher } from './dispatcher';
8
+
9
+ export interface AdbSocketInfo {
10
+ backend: AdbBackend;
11
+
12
+ localId: number;
13
+
14
+ remoteId: number;
15
+
16
+ localCreated: boolean;
17
+
18
+ serviceString: string;
19
+ }
20
+
21
+ export interface AdbSocketConstructionOptions {
22
+ dispatcher: AdbPacketDispatcher;
23
+
24
+ localId: number;
25
+
26
+ remoteId: number;
27
+
28
+ localCreated: boolean;
29
+
30
+ serviceString: string;
31
+ }
32
+
33
+ export class AdbSocketController extends AutoDisposable implements AdbSocketInfo {
34
+ private readonly writeChunkLock = this.addDisposable(new AutoResetEvent());
35
+ private readonly writeLock = this.addDisposable(new AutoResetEvent());
36
+
37
+ private readonly dispatcher!: AdbPacketDispatcher;
38
+ public get backend() { return this.dispatcher.backend; }
39
+
40
+ public readonly localId!: number;
41
+ public readonly remoteId!: number;
42
+ public readonly localCreated!: boolean;
43
+ public readonly serviceString!: string;
44
+
45
+ public readonly dataEvent = this.addDisposable(new DataEventEmitter<ArrayBuffer>());
46
+
47
+ private _closed = false;
48
+ public get closed() { return this._closed; }
49
+
50
+ private readonly closeEvent = this.addDisposable(new CloseEventEmitter());
51
+ public get onClose() { return this.closeEvent.event; }
52
+
53
+ public constructor(options: AdbSocketConstructionOptions) {
54
+ super();
55
+ Object.assign(this, options);
56
+ }
57
+
58
+ private async writeChunk(data: ArrayBuffer): Promise<void> {
59
+ try {
60
+ // Wait for an ack packet
61
+ await this.writeChunkLock.wait();
62
+ } catch {
63
+ // Lock has been disposed, which means the socket has been closed
64
+ throw new Error('Can not write after closed');
65
+ }
66
+
67
+ await this.dispatcher.sendPacket(AdbCommand.Write, this.localId, this.remoteId, data);
68
+ }
69
+
70
+ public async write(data: ArrayBuffer): Promise<void> {
71
+ try {
72
+ // Keep write operations in order
73
+ await this.writeLock.wait();
74
+ } catch {
75
+ // Lock has been disposed, which means the socket has been closed
76
+ throw new Error('Can not write after closed');
77
+ }
78
+
79
+ for await (const chunk of chunkArrayLike(data, this.dispatcher.maxPayloadSize)) {
80
+ await this.writeChunk(chunk);
81
+ }
82
+ this.writeLock.notify();
83
+ }
84
+
85
+ public ack() {
86
+ this.writeChunkLock.notify();
87
+ }
88
+
89
+ public async close(): Promise<void> {
90
+ if (!this._closed) {
91
+ // Immediately cancel all pending writes
92
+ this.writeLock.dispose();
93
+ this.writeChunkLock.dispose();
94
+
95
+ await this.dispatcher.sendPacket(AdbCommand.Close, this.localId, this.remoteId);
96
+ this._closed = true;
97
+ }
98
+ }
99
+
100
+ public override dispose() {
101
+ this._closed = true;
102
+ this.closeEvent.fire();
103
+ super.dispose();
104
+ }
105
+ }
@@ -1,27 +1,27 @@
1
- import { PromiseResolver } from '@yume-chan/async';
2
- import { Event, EventEmitter, EventListenerInfo } from '@yume-chan/event';
3
- import { ValueOrPromise } from '@yume-chan/struct';
4
-
5
- export type AsyncEventResult = ValueOrPromise<void>;
6
-
7
- export type AsyncEvent<TEvent> = Event<TEvent, AsyncEventResult>;
8
-
9
- export class DataEventEmitter<TEvent> extends EventEmitter<TEvent, AsyncEventResult> {
10
- private dispatchLock = new PromiseResolver<void>();
11
-
12
- protected addEventListener(info: EventListenerInfo<TEvent, AsyncEventResult>) {
13
- const remove = super.addEventListener(info);
14
- if (this.listeners.length === 1) {
15
- this.dispatchLock.resolve();
16
- }
17
- return remove;
18
- }
19
-
20
- public async fire(e: TEvent) {
21
- await this.dispatchLock.promise;
22
-
23
- for (const info of this.listeners) {
24
- await info.listener.apply(info.thisArg, [e, ...info.args]);
25
- }
26
- }
27
- }
1
+ import { PromiseResolver } from '@yume-chan/async';
2
+ import { Event, EventEmitter, EventListenerInfo } from '@yume-chan/event';
3
+ import { ValueOrPromise } from '@yume-chan/struct';
4
+
5
+ export type AsyncEventResult = ValueOrPromise<void>;
6
+
7
+ export type AsyncEvent<TEvent> = Event<TEvent, AsyncEventResult>;
8
+
9
+ export class DataEventEmitter<TEvent> extends EventEmitter<TEvent, AsyncEventResult> {
10
+ private dispatchLock = new PromiseResolver<void>();
11
+
12
+ protected override addEventListener(info: EventListenerInfo<TEvent, AsyncEventResult>) {
13
+ const remove = super.addEventListener(info);
14
+ if (this.listeners.length === 1) {
15
+ this.dispatchLock.resolve();
16
+ }
17
+ return remove;
18
+ }
19
+
20
+ public override async fire(e: TEvent) {
21
+ await this.dispatchLock.promise;
22
+
23
+ for (const info of this.listeners) {
24
+ await info.listener.apply(info.thisArg, [e, ...info.args]);
25
+ }
26
+ }
27
+ }