I have a Web Serial port that I want to read some data from. I'd like to use TransformStream
s to do some processing (e.g. decode bytes to strings, separate out logical messages, etc) by using pipeThrough
to transform the data. However, once I do this, I can no longer release the lock on the port by calling reader.releaseLock()
. What am I doing wrong here?
This code works how I expect (running without dependencies in the browser in a secure context):
async serialTestWorking() {
const port = await navigator.serial.requestPort();
await port.open({baudRate: 9600});
console.log("Is locked after open?", port.readable.locked);
// Prints "Is locked after open? false"
let reader = port.readable.getReader();
console.log("Is locked after getReader?", port.readable.locked);
// Prints "Is locked after getReader? true"
reader.releaseLock();
console.log("Is locked after releaseLock?", port.readable.locked);
// Prints "Is locked after releaseLock? false"
await port.close();
console.log("Port closed");
// Prints "Port closed"
}
However, if I use pipeThrough
to send the output through a do-nothing TransformStream
, it all falls apart. The lock isn't released at releaseLock
and the final close
fails to work.
async serialTestBroken() {
const port = await navigator.serial.requestPort();
await port.open({baudRate: 9600});
console.log("Is locked after open?", port.readable.locked);
// Prints "Is locked after open? false"
let reader = port.readable.pipeThrough(new TransformStream()).getReader();
console.log("Is locked after getReader?", port.readable.locked);
// Prints "Is locked after getReader? true"
reader.releaseLock();
console.log("Is locked after releaseLock?", port.readable.locked);
// Prints "Is locked after releaseLock? true"
await port.close();
console.log("Port closed");
// Doesn't make it to the log line
//throws "TypeError: Failed to execute 'close' on 'SerialPort': Cannot cancel a locked stream"
}
What am I doing wrong here? Does releasing the lock on the TransformStream
really not propagate upstream? Do I have to keep track of an instance of every transformer in my pipeline so I can be sure to unlock them all?
The streams spec says that piping locks the readable and writable streams for the duration of the pipe operation.
Piping locks the readable and writable streams, preventing them from being manipulated for the duration of the pipe operation. This allows the implementation to perform important optimizations, such as directly shuttling data from the underlying source to the underlying sink while bypassing many of the intermediate queues.
Is there some other way I have to indicate that the "piping operation" is completed?