feat(adb): don't kill subprocess on stream close

This commit is contained in:
Simon Chan 2023-10-17 21:13:36 +08:00
parent e45fb2ed55
commit fe5cb5a176
No known key found for this signature in database
GPG key ID: A8B69F750B9BCEDD
6 changed files with 102 additions and 77 deletions

View file

@ -5,8 +5,8 @@ import type {
AdbIncomingSocketHandler,
AdbServerConnection,
AdbServerConnectionOptions,
AdbServerConnector,
} from "@yume-chan/adb";
import type { ReadableWritablePair } from "@yume-chan/stream-extra";
import {
PushReadableStream,
UnwrapConsumableStream,
@ -15,12 +15,21 @@ import {
} from "@yume-chan/stream-extra";
import type { ValueOrPromise } from "@yume-chan/struct";
function nodeSocketToStreamPair(socket: Socket) {
function nodeSocketToConnection(socket: Socket): AdbServerConnection {
socket.setNoDelay(true);
const closed = new Promise<void>((resolve) => {
socket.on("close", resolve);
});
return {
readable: new PushReadableStream<Uint8Array>((controller) => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
socket.on("data", async (data) => {
if (controller.abortSignal.aborted) {
return;
}
socket.pause();
await controller.enqueue(data);
socket.resume();
@ -32,9 +41,6 @@ function nodeSocketToStreamPair(socket: Socket) {
// controller already closed
}
});
controller.abortSignal.addEventListener("abort", () => {
socket.end();
});
}),
writable: new WritableStream<Uint8Array>({
write: async (chunk) => {
@ -48,16 +54,17 @@ function nodeSocketToStreamPair(socket: Socket) {
});
});
},
close() {
return new Promise<void>((resolve) => {
socket.end(resolve);
});
},
}),
get closed() {
return closed;
},
close() {
socket.end();
},
};
}
export class AdbServerNodeTcpConnection implements AdbServerConnection {
export class AdbServerNodeTcpConnector implements AdbServerConnector {
readonly spec: SocketConnectOpts;
readonly #listeners = new Map<string, Server>();
@ -68,7 +75,7 @@ export class AdbServerNodeTcpConnection implements AdbServerConnection {
async connect(
{ unref }: AdbServerConnectionOptions = { unref: false },
): Promise<ReadableWritablePair<Uint8Array, Uint8Array>> {
): Promise<AdbServerConnection> {
const socket = new Socket();
if (unref) {
socket.unref();
@ -78,7 +85,7 @@ export class AdbServerNodeTcpConnection implements AdbServerConnection {
socket.once("connect", resolve);
socket.once("error", reject);
});
return nodeSocketToStreamPair(socket);
return nodeSocketToConnection(socket);
}
async addReverseTunnel(
@ -87,16 +94,19 @@ export class AdbServerNodeTcpConnection implements AdbServerConnection {
): Promise<string> {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const server = new Server(async (socket) => {
const stream = nodeSocketToStreamPair(socket);
const connection = nodeSocketToConnection(socket);
try {
await handler({
service: address!,
readable: stream.readable,
readable: connection.readable,
writable: new WrapWritableStream(
stream.writable,
connection.writable,
).bePipedThroughFrom(new UnwrapConsumableStream()),
close() {
socket.end();
get closed() {
return connection.closed;
},
async close() {
await connection.close();
},
});
} catch {