vieter/src/docker/stream.v

100 lines
1.6 KiB
V

module docker
import io
import util
import encoding.binary
import encoding.hex
struct ChunkedResponseReader {
mut:
reader io.Reader
// buf []u8
// offset int
// len int
bytes_left_in_chunk u64
end_of_stream bool
started bool
}
pub fn new_chunked_response_reader(reader io.Reader) &ChunkedResponseReader {
r := &ChunkedResponseReader{
reader: reader
}
return r
}
// We satisfy the io.Reader interface
pub fn (mut r ChunkedResponseReader) read(mut buf []u8) ?int {
if r.end_of_stream {
return none
}
if r.bytes_left_in_chunk == 0 {
r.bytes_left_in_chunk = r.read_chunk_size()?
if r.end_of_stream {
return none
}
}
mut c := 0
if buf.len > r.bytes_left_in_chunk {
c = r.reader.read(mut buf[..r.bytes_left_in_chunk])?
} else {
c = r.reader.read(mut buf)?
}
r.bytes_left_in_chunk -= u64(c)
return c
}
fn (mut r ChunkedResponseReader) read_chunk_size() ?u64 {
mut buf := []u8{len: 2}
mut res := []u8{}
if r.started {
// Each chunk ends with a `\r\n` which we want to skip first
r.reader.read(mut buf) ?
}
r.started = true
for {
c := r.reader.read(mut buf)?
res << buf[..c]
match_len := util.match_array_in_array(buf[..c], http_chunk_separator)
if match_len == http_chunk_separator.len {
break
}
if match_len > 0 {
mut buf2 := []u8{len: 2 - match_len}
c2 := r.reader.read(mut buf2)?
res << buf2[..c2]
if buf2 == http_chunk_separator[match_len..] {
break
}
}
}
mut num_data := hex.decode(res#[..-2].bytestr())?
for num_data.len < 8 {
num_data.insert(0, 0)
}
num := binary.big_endian_u64(num_data)
if num == 0 {
r.end_of_stream = true
}
return num
}