whatwg / streams

Streams Standard
https://streams.spec.whatwg.org/
Other
1.34k stars 157 forks source link

How to create a transformed WritableStream that waits for close? #1222

Open yume-chan opened 2 years ago

yume-chan commented 2 years ago

Now I have this API:

export function adbSyncPush(
    stream: AdbBufferedStream,
    writer: WritableStreamDefaultWriter<Uint8Array>,
    filename: string,
    mode: number = (LinuxFileType.File << 12) | 0o666,
    mtime: number = (Date.now() / 1000) | 0,
    packetSize: number = ADB_SYNC_MAX_PACKET_SIZE,
): WritableStream<Uint8Array> {
    // FIXME: `ChunkStream` can't forward `close` Promise.
    const { readable, writable } = new ChunkStream(packetSize);
    readable.pipeTo(new WritableStream<Uint8Array>({
        async start() {
            const pathAndMode = `${filename},${mode.toString()}`;
            await adbSyncWriteRequest(writer, AdbSyncRequestId.Send, pathAndMode);
        },
        async write(chunk) {
            await adbSyncWriteRequest(writer, AdbSyncRequestId.Data, chunk);
        },
        async close() {
            await adbSyncWriteRequest(writer, AdbSyncRequestId.Done, mtime);
            await adbSyncReadResponse(stream, ResponseTypes);
        }
    }, {
        highWaterMark: 16 * 1024,
        size(chunk) { return chunk.byteLength; }
    }));
    return writable;
}

It returns a WrtiableStream to let the caller write a file on device, the close handler tells the device to finish the file and return the final result. Let's call it PushFileStream.

Because each packet can't exceed packetSize length, I need to split each incoming chunks. I think I can re-use the ChunkStream (a TransformStream) that's used somewhere else, so I piped the readable end to PushFileStream, and returned the writable end of the ChunkStream to callers.

It can correctly chunk the incoming data and send them to device, however, the writable of ChunkStream won't wait for close of PushFileStream. If the caller want to close the stream and writer after finishing pushing, they may be closed before close, causing push to fail.

So how can I wait for PushFileStream close, or how can I generally use TransformStream when creating a WritableStream?