javascriptstreamweb-standards

Get partial range of ReadableStream


I want to return a specific byte range given a ReadableStream. It sounds easy but I can't find any way to skip through or read a specific amount of bytes from the stream since we can only read chunks. I would prefer to not store any data and just send the stream. It sounds like I could do this with a TransformStream and PipeThrough(). But I need some help wrapping my head around it.

Example: Given a ReadableStream of say 1000 bytes, I want to return another stream that starts at byte 300 and ends at byte 900.

I know this can easily be done with nodes createReadableStream(), but I need to run this in the browser so it cant use node.


Solution

  • Here's some skeleton code to get you started:

    function byteRangeTransform(start, end) {
      let bytesSeen = 0;
      return new TransformStream({
        transform(chunk, controller) {
          const chunkStart = bytesSeen;
          const chunkEnd = bytesSeen + chunk.byteLength;
          bytesSeen += chunk.byteLength;
          
          // Six cases:
    
          // 1. Chunk entirely before start
          if (chunkEnd < start) {
            return;
          }
          
          // 2. Chunk starts before start, ends between start and end
          if (chunkStart < start && chunkEnd >= start && chunkEnd <= end) {
            const slice = /* TODO */;
            controller.enqueue(slice);
            return;
          }
          
          // 3. Chunk starts before start, ends after end
          if (chunkStart < start && chunkEnd > end) {
            // TODO
          }
    
          // 4. Chunk starts after start, ends between start and end
          // 5. Chunk starts after start, ends after end
          // 6. Chunk starts after end
        }
      });
    }
    
    const onlyInRange = originalReadable.pipeThrough(byteRangeTransform(300, 900));