@yume-chan/adb 0.0.15 → 0.0.16

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 (103) hide show
  1. package/CHANGELOG.json +21 -0
  2. package/CHANGELOG.md +11 -1
  3. package/LICENSE +21 -21
  4. package/README.md +247 -247
  5. package/esm/adb.d.ts +7 -0
  6. package/esm/adb.d.ts.map +1 -1
  7. package/esm/adb.js +7 -0
  8. package/esm/adb.js.map +1 -1
  9. package/esm/commands/subprocess/protocols/none.d.ts +1 -0
  10. package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
  11. package/esm/commands/subprocess/protocols/none.js +6 -5
  12. package/esm/commands/subprocess/protocols/none.js.map +1 -1
  13. package/esm/commands/sync/stat.d.ts.map +1 -1
  14. package/esm/commands/sync/stat.js.map +1 -1
  15. package/esm/socket/dispatcher.d.ts +4 -1
  16. package/esm/socket/dispatcher.d.ts.map +1 -1
  17. package/esm/socket/dispatcher.js +11 -8
  18. package/esm/socket/dispatcher.js.map +1 -1
  19. package/esm/socket/socket.d.ts +6 -1
  20. package/esm/socket/socket.d.ts.map +1 -1
  21. package/esm/socket/socket.js +17 -7
  22. package/esm/socket/socket.js.map +1 -1
  23. package/esm/stream/buffered.d.ts +6 -2
  24. package/esm/stream/buffered.d.ts.map +1 -1
  25. package/esm/stream/buffered.js +67 -47
  26. package/esm/stream/buffered.js.map +1 -1
  27. package/esm/stream/detect.js +1 -0
  28. package/esm/stream/detect.js.map +1 -1
  29. package/esm/stream/detect.polyfill.d.ts.map +1 -1
  30. package/esm/stream/detect.polyfill.js +0 -5
  31. package/esm/stream/detect.polyfill.js.map +1 -1
  32. package/esm/stream/transform.d.ts +20 -0
  33. package/esm/stream/transform.d.ts.map +1 -1
  34. package/esm/stream/transform.js +7 -1
  35. package/esm/stream/transform.js.map +1 -1
  36. package/package.json +10 -10
  37. package/src/adb.ts +280 -273
  38. package/src/auth.ts +173 -173
  39. package/src/backend.ts +11 -11
  40. package/src/commands/base.ts +11 -11
  41. package/src/commands/framebuffer.ts +73 -73
  42. package/src/commands/index.ts +8 -8
  43. package/src/commands/install.ts +30 -30
  44. package/src/commands/power.ts +54 -54
  45. package/src/commands/reverse.ts +140 -140
  46. package/src/commands/subprocess/index.ts +139 -139
  47. package/src/commands/subprocess/protocols/none.ts +70 -68
  48. package/src/commands/subprocess/protocols/shell.ts +190 -190
  49. package/src/commands/subprocess/protocols/types.ts +59 -59
  50. package/src/commands/subprocess/utils.ts +20 -20
  51. package/src/commands/sync/index.ts +7 -7
  52. package/src/commands/sync/list.ts +86 -86
  53. package/src/commands/sync/pull.ts +46 -46
  54. package/src/commands/sync/push.ts +41 -41
  55. package/src/commands/sync/request.ts +50 -50
  56. package/src/commands/sync/response.ts +64 -64
  57. package/src/commands/sync/stat.ts +151 -150
  58. package/src/commands/sync/sync.ts +181 -181
  59. package/src/commands/tcpip.ts +21 -21
  60. package/src/crypto.ts +296 -296
  61. package/src/features.ts +9 -9
  62. package/src/index.ts +11 -11
  63. package/src/packet.ts +80 -80
  64. package/src/socket/dispatcher.ts +305 -304
  65. package/src/socket/index.ts +2 -2
  66. package/src/socket/socket.ts +155 -144
  67. package/src/stream/buffered.ts +168 -147
  68. package/src/stream/detect.native.ts +362 -362
  69. package/src/stream/detect.polyfill.ts +22 -28
  70. package/src/stream/detect.ts +7 -5
  71. package/src/stream/index.ts +3 -3
  72. package/src/stream/transform.ts +474 -447
  73. package/src/utils/auto-reset-event.ts +41 -41
  74. package/src/utils/base64.ts +306 -306
  75. package/src/utils/index.ts +3 -3
  76. package/tsconfig.build.json +3 -3
  77. package/tsconfig.build.tsbuildinfo +1 -1
  78. package/tsconfig.test.json +9 -10
  79. package/web-streams-polyfill-4.0.0-beta.2.tgz +0 -0
  80. package/esm/commands/subprocess/legacy.d.ts +0 -35
  81. package/esm/commands/subprocess/legacy.d.ts.map +0 -1
  82. package/esm/commands/subprocess/legacy.js +0 -53
  83. package/esm/commands/subprocess/legacy.js.map +0 -1
  84. package/esm/commands/subprocess/protocol.d.ts +0 -39
  85. package/esm/commands/subprocess/protocol.d.ts.map +0 -1
  86. package/esm/commands/subprocess/protocol.js +0 -157
  87. package/esm/commands/subprocess/protocol.js.map +0 -1
  88. package/esm/commands/subprocess/types.d.ts +0 -50
  89. package/esm/commands/subprocess/types.d.ts.map +0 -1
  90. package/esm/commands/subprocess/types.js +0 -2
  91. package/esm/commands/subprocess/types.js.map +0 -1
  92. package/esm/socket/controller.d.ts +0 -37
  93. package/esm/socket/controller.d.ts.map +0 -1
  94. package/esm/socket/controller.js +0 -66
  95. package/esm/socket/controller.js.map +0 -1
  96. package/esm/stream/detect.bak.d.ts +0 -240
  97. package/esm/stream/detect.bak.d.ts.map +0 -1
  98. package/esm/stream/detect.bak.js +0 -60
  99. package/esm/stream/detect.bak.js.map +0 -1
  100. package/esm/utils/encoding.d.ts +0 -3
  101. package/esm/utils/encoding.d.ts.map +0 -1
  102. package/esm/utils/encoding.js +0 -11
  103. package/esm/utils/encoding.js.map +0 -1
@@ -1,144 +1,155 @@
1
- import { PromiseResolver } from "@yume-chan/async";
2
- import type { Disposable } from "@yume-chan/event";
3
- import { AdbCommand } from '../packet.js';
4
- import { ChunkStream, DuplexStreamFactory, pipeFrom, PushReadableStream, WritableStream, type PushReadableStreamController, type ReadableStream, type ReadableWritablePair } from '../stream/index.js';
5
- import type { AdbPacketDispatcher, Closeable } from './dispatcher.js';
6
-
7
- export interface AdbSocketInfo {
8
- localId: number;
9
- remoteId: number;
10
-
11
- localCreated: boolean;
12
- serviceString: string;
13
- }
14
-
15
- export interface AdbSocketConstructionOptions extends AdbSocketInfo {
16
- dispatcher: AdbPacketDispatcher;
17
-
18
- highWaterMark?: number | undefined;
19
- }
20
-
21
- export class AdbSocketController implements AdbSocketInfo, ReadableWritablePair<Uint8Array, Uint8Array>, Closeable, Disposable {
22
- private readonly dispatcher!: AdbPacketDispatcher;
23
-
24
- public readonly localId!: number;
25
- public readonly remoteId!: number;
26
- public readonly localCreated!: boolean;
27
- public readonly serviceString!: string;
28
-
29
- private _factory: DuplexStreamFactory<Uint8Array, Uint8Array>;
30
-
31
- private _readable: ReadableStream<Uint8Array>;
32
- private _readableController!: PushReadableStreamController<Uint8Array>;
33
- public get readable() { return this._readable; }
34
-
35
- private _writePromise: PromiseResolver<void> | undefined;
36
- public readonly writable: WritableStream<Uint8Array>;
37
-
38
- private _closed = false;
39
- public get closed() { return this._closed; }
40
-
41
- private _socket: AdbSocket;
42
- public get socket() { return this._socket; }
43
-
44
- public constructor(options: AdbSocketConstructionOptions) {
45
- Object.assign(this, options);
46
-
47
- // Check this image to help you understand the stream graph
48
- // cspell: disable-next-line
49
- // https://www.plantuml.com/plantuml/png/TL0zoeGm4ErpYc3l5JxyS0yWM6mX5j4C6p4cxcJ25ejttuGX88ZftizxUKmJI275pGhXl0PP_UkfK_CAz5Z2hcWsW9Ny2fdU4C1f5aSchFVxA8vJjlTPRhqZzDQMRB7AklwJ0xXtX0ZSKH1h24ghoKAdGY23FhxC4nS2pDvxzIvxb-8THU0XlEQJ-ZB7SnXTAvc_LhOckhMdLBnbtndpb-SB7a8q2SRD_W00
50
-
51
- this._factory = new DuplexStreamFactory<Uint8Array, Uint8Array>({
52
- close: async () => {
53
- await this.dispatcher.sendPacket(
54
- AdbCommand.Close,
55
- this.localId,
56
- this.remoteId
57
- );
58
-
59
- // Don't `dispose` here, we need to wait for `CLSE` response packet.
60
- return false;
61
- },
62
- dispose: () => {
63
- this._closed = true;
64
-
65
- // Error out the pending writes
66
- this._writePromise?.reject(new Error('Socket closed'));
67
- },
68
- });
69
-
70
- this._readable = this._factory.wrapReadable(
71
- new PushReadableStream(controller => {
72
- this._readableController = controller;
73
- }, {
74
- highWaterMark: options.highWaterMark ?? 16 * 1024,
75
- size(chunk) { return chunk.byteLength; }
76
- })
77
- );
78
-
79
- this.writable = pipeFrom(
80
- this._factory.createWritable(
81
- new WritableStream({
82
- write: async (chunk) => {
83
- // Wait for an ack packet
84
- this._writePromise = new PromiseResolver();
85
- await this.dispatcher.sendPacket(
86
- AdbCommand.Write,
87
- this.localId,
88
- this.remoteId,
89
- chunk
90
- );
91
- await this._writePromise.promise;
92
- }
93
- }),
94
- ),
95
- new ChunkStream(this.dispatcher.options.maxPayloadSize)
96
- );
97
-
98
- this._socket = new AdbSocket(this);
99
- }
100
-
101
- public async enqueue(packet: Uint8Array) {
102
- await this._readableController.enqueue(packet);
103
- }
104
-
105
- public ack() {
106
- this._writePromise?.resolve();
107
- }
108
-
109
- public async close(): Promise<void> {
110
- this._factory.close();
111
- }
112
-
113
- public dispose() {
114
- this._factory.dispose();
115
- }
116
- }
117
-
118
- /**
119
- * AdbSocket is a duplex stream.
120
- *
121
- * To close it, call either `socket.close()`,
122
- * `socket.readable.cancel()`, `socket.readable.getReader().cancel()`,
123
- * `socket.writable.abort()`, `socket.writable.getWriter().abort()`,
124
- * `socket.writable.close()` or `socket.writable.getWriter().close()`.
125
- */
126
- export class AdbSocket implements AdbSocketInfo, ReadableWritablePair<Uint8Array, Uint8Array>{
127
- private _controller: AdbSocketController;
128
-
129
- public get localId(): number { return this._controller.localId; }
130
- public get remoteId(): number { return this._controller.remoteId; }
131
- public get localCreated(): boolean { return this._controller.localCreated; }
132
- public get serviceString(): string { return this._controller.serviceString; }
133
-
134
- public get readable(): ReadableStream<Uint8Array> { return this._controller.readable; }
135
- public get writable(): WritableStream<Uint8Array> { return this._controller.writable; }
136
-
137
- public constructor(controller: AdbSocketController) {
138
- this._controller = controller;
139
- }
140
-
141
- public close() {
142
- return this._controller.close();
143
- }
144
- }
1
+ import { PromiseResolver } from "@yume-chan/async";
2
+ import type { Disposable } from "@yume-chan/event";
3
+ import { AdbCommand } from '../packet.js';
4
+ import { ChunkStream, DuplexStreamFactory, pipeFrom, PushReadableStream, WritableStream, type PushReadableStreamController, type ReadableStream, type ReadableWritablePair } from '../stream/index.js';
5
+ import type { AdbPacketDispatcher, Closeable } from './dispatcher.js';
6
+
7
+ export interface AdbSocketInfo {
8
+ localId: number;
9
+ remoteId: number;
10
+
11
+ localCreated: boolean;
12
+ serviceString: string;
13
+ }
14
+
15
+ export interface AdbSocketConstructionOptions extends AdbSocketInfo {
16
+ dispatcher: AdbPacketDispatcher;
17
+
18
+ highWaterMark?: number | undefined;
19
+ }
20
+
21
+ export class AdbSocketController implements AdbSocketInfo, ReadableWritablePair<Uint8Array, Uint8Array>, Closeable, Disposable {
22
+ private readonly dispatcher!: AdbPacketDispatcher;
23
+
24
+ public readonly localId!: number;
25
+ public readonly remoteId!: number;
26
+ public readonly localCreated!: boolean;
27
+ public readonly serviceString!: string;
28
+
29
+ private _duplex: DuplexStreamFactory<Uint8Array, Uint8Array>;
30
+
31
+ private _readable: ReadableStream<Uint8Array>;
32
+ private _readableController!: PushReadableStreamController<Uint8Array>;
33
+ public get readable() { return this._readable; }
34
+
35
+ private _writePromise: PromiseResolver<void> | undefined;
36
+ public readonly writable: WritableStream<Uint8Array>;
37
+
38
+ private _closed = false;
39
+ /**
40
+ * Whether the socket is half-closed (i.e. the local side initiated the close).
41
+ *
42
+ * It's only used by dispatcher to avoid sending another `CLSE` packet to remote.
43
+ */
44
+ public get closed() { return this._closed; }
45
+
46
+ private _socket: AdbSocket;
47
+ public get socket() { return this._socket; }
48
+
49
+ public constructor(options: AdbSocketConstructionOptions) {
50
+ Object.assign(this, options);
51
+
52
+ // Check this image to help you understand the stream graph
53
+ // cspell: disable-next-line
54
+ // https://www.plantuml.com/plantuml/png/TL0zoeGm4ErpYc3l5JxyS0yWM6mX5j4C6p4cxcJ25ejttuGX88ZftizxUKmJI275pGhXl0PP_UkfK_CAz5Z2hcWsW9Ny2fdU4C1f5aSchFVxA8vJjlTPRhqZzDQMRB7AklwJ0xXtX0ZSKH1h24ghoKAdGY23FhxC4nS2pDvxzIvxb-8THU0XlEQJ-ZB7SnXTAvc_LhOckhMdLBnbtndpb-SB7a8q2SRD_W00
55
+
56
+ this._duplex = new DuplexStreamFactory<Uint8Array, Uint8Array>({
57
+ close: async () => {
58
+ this._closed = true;
59
+
60
+ await this.dispatcher.sendPacket(
61
+ AdbCommand.Close,
62
+ this.localId,
63
+ this.remoteId
64
+ );
65
+
66
+ // Don't `dispose` here, we need to wait for `CLSE` response packet.
67
+ return false;
68
+ },
69
+ dispose: () => {
70
+ // Error out the pending writes
71
+ this._writePromise?.reject(new Error('Socket closed'));
72
+ },
73
+ });
74
+
75
+ this._readable = this._duplex.wrapReadable(
76
+ new PushReadableStream(controller => {
77
+ this._readableController = controller;
78
+ }, {
79
+ highWaterMark: options.highWaterMark ?? 16 * 1024,
80
+ size(chunk) { return chunk.byteLength; }
81
+ })
82
+ );
83
+
84
+ this.writable = pipeFrom(
85
+ this._duplex.createWritable(
86
+ new WritableStream({
87
+ write: async (chunk) => {
88
+ // Wait for an ack packet
89
+ this._writePromise = new PromiseResolver();
90
+ await this.dispatcher.sendPacket(
91
+ AdbCommand.Write,
92
+ this.localId,
93
+ this.remoteId,
94
+ chunk
95
+ );
96
+ await this._writePromise.promise;
97
+ }
98
+ }),
99
+ ),
100
+ new ChunkStream(this.dispatcher.options.maxPayloadSize)
101
+ );
102
+
103
+ this._socket = new AdbSocket(this);
104
+ }
105
+
106
+ public async enqueue(packet: Uint8Array) {
107
+ // Consumer may abort the `ReadableStream` to close the socket,
108
+ // it's OK to throw away further packets in this case.
109
+ if (this._readableController.abortSignal.aborted) {
110
+ return;
111
+ }
112
+
113
+ await this._readableController.enqueue(packet);
114
+ }
115
+
116
+ public ack() {
117
+ this._writePromise?.resolve();
118
+ }
119
+
120
+ public async close(): Promise<void> {
121
+ await this._duplex.close();
122
+ }
123
+
124
+ public dispose() {
125
+ this._duplex.dispose();
126
+ }
127
+ }
128
+
129
+ /**
130
+ * AdbSocket is a duplex stream.
131
+ *
132
+ * To close it, call either `socket.close()`,
133
+ * `socket.readable.cancel()`, `socket.readable.getReader().cancel()`,
134
+ * `socket.writable.abort()`, `socket.writable.getWriter().abort()`,
135
+ * `socket.writable.close()` or `socket.writable.getWriter().close()`.
136
+ */
137
+ export class AdbSocket implements AdbSocketInfo, ReadableWritablePair<Uint8Array, Uint8Array>{
138
+ private _controller: AdbSocketController;
139
+
140
+ public get localId(): number { return this._controller.localId; }
141
+ public get remoteId(): number { return this._controller.remoteId; }
142
+ public get localCreated(): boolean { return this._controller.localCreated; }
143
+ public get serviceString(): string { return this._controller.serviceString; }
144
+
145
+ public get readable(): ReadableStream<Uint8Array> { return this._controller.readable; }
146
+ public get writable(): WritableStream<Uint8Array> { return this._controller.writable; }
147
+
148
+ public constructor(controller: AdbSocketController) {
149
+ this._controller = controller;
150
+ }
151
+
152
+ public close() {
153
+ return this._controller.close();
154
+ }
155
+ }
@@ -1,147 +1,168 @@
1
- import type { StructAsyncDeserializeStream } from '@yume-chan/struct';
2
- import type { AdbSocket, AdbSocketInfo } from '../socket/index.js';
3
- import type { ReadableStream, ReadableStreamDefaultReader } from './detect.js';
4
- import { PushReadableStream } from "./transform.js";
5
-
6
- export class BufferedStreamEndedError extends Error {
7
- public constructor() {
8
- super('Stream ended');
9
-
10
- // Fix Error's prototype chain when compiling to ES5
11
- Object.setPrototypeOf(this, new.target.prototype);
12
- }
13
- }
14
-
15
- export class BufferedStream {
16
- private buffer: Uint8Array | undefined;
17
-
18
- protected readonly stream: ReadableStream<Uint8Array>;
19
-
20
- protected readonly reader: ReadableStreamDefaultReader<Uint8Array>;
21
-
22
- public constructor(stream: ReadableStream<Uint8Array>) {
23
- this.stream = stream;
24
- this.reader = stream.getReader();
25
- }
26
-
27
- /**
28
- *
29
- * @param length
30
- * @returns
31
- */
32
- public async read(length: number): Promise<Uint8Array> {
33
- let array: Uint8Array;
34
- let index: number;
35
- if (this.buffer) {
36
- const buffer = this.buffer;
37
- if (buffer.byteLength > length) {
38
- this.buffer = buffer.subarray(length);
39
- return buffer.subarray(0, length);
40
- }
41
-
42
- array = new Uint8Array(length);
43
- array.set(buffer);
44
- index = buffer.byteLength;
45
- this.buffer = undefined;
46
- } else {
47
- const { done, value } = await this.reader.read();
48
- if (done) {
49
- throw new BufferedStreamEndedError();
50
- }
51
-
52
- if (value.byteLength === length) {
53
- return value;
54
- }
55
-
56
- if (value.byteLength > length) {
57
- this.buffer = value.subarray(length);
58
- return value.subarray(0, length);
59
- }
60
-
61
- array = new Uint8Array(length);
62
- array.set(value);
63
- index = value.byteLength;
64
- }
65
-
66
- while (index < length) {
67
- const left = length - index;
68
-
69
- const { done, value } = await this.reader.read();
70
- if (done) {
71
- throw new BufferedStreamEndedError();
72
- }
73
-
74
- if (value.byteLength === left) {
75
- array.set(value, index);
76
- return array;
77
- }
78
-
79
- if (value.byteLength > left) {
80
- array.set(value.subarray(0, left), index);
81
- this.buffer = value.subarray(left);
82
- return array;
83
- }
84
-
85
- array.set(value, index);
86
- index += value.byteLength;
87
- }
88
-
89
- return array;
90
- }
91
-
92
- /**
93
- * Return a readable stream with unconsumed data (if any) and
94
- * all data from the wrapped stream.
95
- * @returns A `ReadableStream`
96
- */
97
- public release(): ReadableStream<Uint8Array> {
98
- if (this.buffer) {
99
- return new PushReadableStream<Uint8Array>(async controller => {
100
- // Put the remaining data back to the stream
101
- await controller.enqueue(this.buffer!);
102
-
103
- // Manually pipe the stream
104
- while (true) {
105
- try {
106
- const { done, value } = await this.reader.read();
107
- if (done) {
108
- controller.close();
109
- break;
110
- } else {
111
- await controller.enqueue(value);
112
- }
113
- } catch (e) {
114
- controller.error(e);
115
- break;
116
- }
117
- }
118
- });
119
- } else {
120
- // Simply release the reader and return the stream
121
- this.reader.releaseLock();
122
- return this.stream;
123
- }
124
- }
125
-
126
- public async close() {
127
- await this.reader.cancel();
128
- }
129
- }
130
-
131
- export class AdbBufferedStream
132
- extends BufferedStream
133
- implements AdbSocketInfo, StructAsyncDeserializeStream {
134
- protected readonly socket: AdbSocket;
135
-
136
- public get localId() { return this.socket.localId; }
137
- public get remoteId() { return this.socket.remoteId; }
138
- public get localCreated() { return this.socket.localCreated; }
139
- public get serviceString() { return this.socket.serviceString; }
140
-
141
- public get writable() { return this.socket.writable; }
142
-
143
- public constructor(socket: AdbSocket) {
144
- super(socket.readable);
145
- this.socket = socket;
146
- }
147
- }
1
+ import type { StructAsyncDeserializeStream } from '@yume-chan/struct';
2
+ import type { AdbSocket, AdbSocketInfo } from '../socket/index.js';
3
+ import type { ReadableStream, ReadableStreamDefaultReader } from './detect.js';
4
+ import { PushReadableStream } from "./transform.js";
5
+
6
+ export class BufferedStreamEndedError extends Error {
7
+ public constructor() {
8
+ super('Stream ended');
9
+
10
+ // Fix Error's prototype chain when compiling to ES5
11
+ Object.setPrototypeOf(this, new.target.prototype);
12
+ }
13
+ }
14
+
15
+ export class BufferedStream {
16
+ private buffered: Uint8Array | undefined;
17
+ private bufferedOffset = 0;
18
+ private bufferedLength = 0;
19
+
20
+ protected readonly stream: ReadableStream<Uint8Array>;
21
+
22
+ protected readonly reader: ReadableStreamDefaultReader<Uint8Array>;
23
+
24
+ public constructor(stream: ReadableStream<Uint8Array>) {
25
+ this.stream = stream;
26
+ this.reader = stream.getReader();
27
+ }
28
+
29
+ private async readSource() {
30
+ const { done, value } = await this.reader.read();
31
+ if (done) {
32
+ throw new BufferedStreamEndedError();
33
+ }
34
+ return value;
35
+ }
36
+
37
+ private async readAsync(length: number, initial?: Uint8Array) {
38
+ let result: Uint8Array;
39
+ let index: number;
40
+
41
+ if (initial) {
42
+ result = new Uint8Array(length);
43
+ result.set(initial);
44
+ index = initial.byteLength;
45
+ length -= initial.byteLength;
46
+ } else {
47
+ const array = await this.readSource();
48
+ if (array.byteLength === length) {
49
+ return array;
50
+ }
51
+
52
+ if (array.byteLength > length) {
53
+ this.buffered = array;
54
+ this.bufferedOffset = length;
55
+ this.bufferedLength = array.byteLength - length;
56
+ return array.subarray(0, length);
57
+ }
58
+
59
+ result = new Uint8Array(length);
60
+ result.set(array);
61
+ index = array.byteLength;
62
+ length -= array.byteLength;
63
+ }
64
+
65
+ while (length > 0) {
66
+ const array = await this.readSource();
67
+ if (array.byteLength === length) {
68
+ result.set(array, index);
69
+ return result;
70
+ }
71
+
72
+ if (array.byteLength > length) {
73
+ this.buffered = array;
74
+ this.bufferedOffset = length;
75
+ this.bufferedLength = array.byteLength - length;
76
+ result.set(array.subarray(0, length), index);
77
+ return result;
78
+ }
79
+
80
+ result.set(array, index);
81
+ index += array.byteLength;
82
+ length -= array.byteLength;
83
+ }
84
+
85
+ return result;
86
+ }
87
+
88
+ /**
89
+ *
90
+ * @param length
91
+ * @returns
92
+ */
93
+ public read(length: number): Uint8Array | Promise<Uint8Array> {
94
+ // PERF: Add a synchronous path for reading from internal buffer
95
+ if (this.buffered) {
96
+ const array = this.buffered;
97
+ const offset = this.bufferedOffset;
98
+ if (this.bufferedLength > length) {
99
+ // PERF: `subarray` is slow
100
+ // don't use it until absolutely necessary
101
+ this.bufferedOffset += length;
102
+ this.bufferedLength -= length;
103
+ return array.subarray(offset, offset + length);
104
+ }
105
+
106
+ this.buffered = undefined;
107
+ return this.readAsync(length, array.subarray(offset));
108
+ }
109
+
110
+ return this.readAsync(length);
111
+ }
112
+
113
+ /**
114
+ * Return a readable stream with unconsumed data (if any) and
115
+ * all data from the wrapped stream.
116
+ * @returns A `ReadableStream`
117
+ */
118
+ public release(): ReadableStream<Uint8Array> {
119
+ if (this.buffered) {
120
+ return new PushReadableStream<Uint8Array>(async controller => {
121
+ // Put the remaining data back to the stream
122
+ await controller.enqueue(this.buffered!);
123
+
124
+ // Manually pipe the stream
125
+ while (true) {
126
+ try {
127
+ const { done, value } = await this.reader.read();
128
+ if (done) {
129
+ controller.close();
130
+ break;
131
+ } else {
132
+ await controller.enqueue(value);
133
+ }
134
+ } catch (e) {
135
+ controller.error(e);
136
+ break;
137
+ }
138
+ }
139
+ });
140
+ } else {
141
+ // Simply release the reader and return the stream
142
+ this.reader.releaseLock();
143
+ return this.stream;
144
+ }
145
+ }
146
+
147
+ public async close() {
148
+ await this.reader.cancel();
149
+ }
150
+ }
151
+
152
+ export class AdbBufferedStream
153
+ extends BufferedStream
154
+ implements AdbSocketInfo, StructAsyncDeserializeStream {
155
+ protected readonly socket: AdbSocket;
156
+
157
+ public get localId() { return this.socket.localId; }
158
+ public get remoteId() { return this.socket.remoteId; }
159
+ public get localCreated() { return this.socket.localCreated; }
160
+ public get serviceString() { return this.socket.serviceString; }
161
+
162
+ public get writable() { return this.socket.writable; }
163
+
164
+ public constructor(socket: AdbSocket) {
165
+ super(socket.readable);
166
+ this.socket = socket;
167
+ }
168
+ }