diff --git a/libraries/adb/src/commands/reverse.ts b/libraries/adb/src/commands/reverse.ts index d621b0a69..25d82b707 100644 --- a/libraries/adb/src/commands/reverse.ts +++ b/libraries/adb/src/commands/reverse.ts @@ -38,7 +38,7 @@ const AdbReverseErrorResponse = new Struct() .concat(AdbReverseStringResponse) .postDeserialize((value) => { // https://issuetracker.google.com/issues/37066218 - // ADB on Android <9 can't create reverse tunnels when connected wirelessly (ADB over WiFi), + // ADB on Android <9 can't create reverse tunnels when connected wirelessly (ADB over Wi-Fi), // and returns this confusing "more than one device/emulator" error. if (value.content === "more than one device/emulator") { throw new AdbReverseNotSupportedError(); diff --git a/libraries/adb/src/commands/subprocess/protocols/shell.ts b/libraries/adb/src/commands/subprocess/protocols/shell.ts index 2a087e3fd..3ec294c4a 100644 --- a/libraries/adb/src/commands/subprocess/protocols/shell.ts +++ b/libraries/adb/src/commands/subprocess/protocols/shell.ts @@ -6,12 +6,10 @@ import type { WritableStreamDefaultWriter, } from "@yume-chan/stream-extra"; import { - ConsumableTransformStream, ConsumableWritableStream, PushReadableStream, StructDeserializeStream, WritableStream, - pipeFrom, } from "@yume-chan/stream-extra"; import type { StructValueType } from "@yume-chan/struct"; import Struct, { placeholder } from "@yume-chan/struct"; @@ -37,68 +35,8 @@ const AdbShellProtocolPacket = new Struct({ littleEndian: true }) .uint32("length") .uint8Array("data", { lengthField: "length" }); -type AdbShellProtocolPacketInit = (typeof AdbShellProtocolPacket)["TInit"]; - type AdbShellProtocolPacket = StructValueType; -class StdinSerializeStream extends ConsumableTransformStream< - Uint8Array, - AdbShellProtocolPacketInit -> { - constructor() { - super({ - async transform(chunk, controller) { - await controller.enqueue({ - id: AdbShellProtocolId.Stdin, - data: chunk, - }); - }, - flush() { - // TODO: AdbShellSubprocessProtocol: support closing stdin - }, - }); - } -} - -class MultiplexStream { - #readable: PushReadableStream; - #readableController!: PushReadableStreamController; - get readable() { - return this.#readable; - } - - #activeCount = 0; - - constructor() { - this.#readable = new PushReadableStream((controller) => { - this.#readableController = controller; - }); - } - - createWriteable() { - return new WritableStream({ - start: () => { - this.#activeCount += 1; - }, - write: async (chunk) => { - await this.#readableController.enqueue(chunk); - }, - abort: () => { - this.#activeCount -= 1; - if (this.#activeCount === 0) { - this.#readableController.close(); - } - }, - close: () => { - this.#activeCount -= 1; - if (this.#activeCount === 0) { - this.#readableController.close(); - } - }, - }); - } -} - /** * Shell v2 a.k.a Shell Protocol * @@ -126,9 +64,7 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol { } readonly #socket: AdbSocket; - #socketWriter: WritableStreamDefaultWriter< - Consumable - >; + #writer: WritableStreamDefaultWriter>; #stdin: WritableStream>; get stdin() { @@ -207,39 +143,33 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol { }, ); - const multiplexer = new MultiplexStream< - Consumable - >(); - void multiplexer.readable - .pipeThrough( - new ConsumableTransformStream({ - async transform(chunk, controller) { - await controller.enqueue( - AdbShellProtocolPacket.serialize(chunk), - ); - }, - }), - ) - .pipeTo(socket.writable); - - this.#stdin = pipeFrom( - multiplexer.createWriteable(), - new StdinSerializeStream(), - ); + this.#writer = this.#socket.writable.getWriter(); - this.#socketWriter = multiplexer.createWriteable().getWriter(); + this.#stdin = new WritableStream>({ + write: async (chunk) => { + await ConsumableWritableStream.write( + this.#writer, + AdbShellProtocolPacket.serialize({ + id: AdbShellProtocolId.Stdin, + data: chunk.value, + }), + ); + chunk.consume(); + }, + }); } async resize(rows: number, cols: number) { - await ConsumableWritableStream.write(this.#socketWriter, { - id: AdbShellProtocolId.WindowSizeChange, - data: encodeUtf8( + await ConsumableWritableStream.write( + this.#writer, + AdbShellProtocolPacket.serialize({ + id: AdbShellProtocolId.WindowSizeChange, // The "correct" format is `${rows}x${cols},${x_pixels}x${y_pixels}` // However, according to https://linux.die.net/man/4/tty_ioctl // `x_pixels` and `y_pixels` are unused, so always sending `0` should be fine. - `${rows}x${cols},0x0\0`, - ), - }); + data: encodeUtf8(`${rows}x${cols},0x0\0`), + }), + ); } kill() { diff --git a/libraries/adb/src/commands/subprocess/utils.ts b/libraries/adb/src/commands/subprocess/utils.ts index 25d3eca75..edfba3aa6 100644 --- a/libraries/adb/src/commands/subprocess/utils.ts +++ b/libraries/adb/src/commands/subprocess/utils.ts @@ -10,7 +10,7 @@ export function escapeArg(s: string) { break; } result += s.substring(base, found); - // a'b becomes a'\'b + // a'b becomes a'\'b (the backslash is not a escape character) result += String.raw`'\''`; base = found + 1; }