63 lines
1.5 KiB
Go
63 lines
1.5 KiB
Go
package streams
|
|
|
|
import (
|
|
"io"
|
|
)
|
|
|
|
type MetadataInjector struct {
|
|
io.Reader
|
|
MetadataInterval int
|
|
blockOffset int
|
|
Metadata Metadata
|
|
metadataBuf []byte
|
|
}
|
|
|
|
func NewMetadataInjector(r io.Reader, metadataInterval int) *MetadataInjector {
|
|
return &MetadataInjector{
|
|
Reader: r,
|
|
MetadataInterval: metadataInterval,
|
|
}
|
|
}
|
|
|
|
func (mi *MetadataInjector) Read(data []byte) (n int, err error) {
|
|
if mi.metadataBuf != nil && len(mi.metadataBuf) > 0 {
|
|
bytesToRead := len(data)
|
|
if bytesToRead < len(mi.metadataBuf) {
|
|
// only read as much as possible
|
|
copy(data, mi.metadataBuf[0:bytesToRead])
|
|
n = bytesToRead
|
|
mi.metadataBuf = mi.metadataBuf[bytesToRead:]
|
|
return
|
|
}
|
|
// read everything
|
|
copy(data, mi.metadataBuf)
|
|
n = len(mi.metadataBuf)
|
|
mi.metadataBuf = nil
|
|
return
|
|
}
|
|
|
|
bytesToRead := mi.MetadataInterval - mi.blockOffset
|
|
if bytesToRead > len(data) {
|
|
bytesToRead = len(data)
|
|
}
|
|
if bytesToRead > 0 {
|
|
n, err = mi.Reader.Read(data[0:bytesToRead])
|
|
if err != nil {
|
|
return
|
|
}
|
|
mi.blockOffset += n
|
|
}
|
|
if mi.blockOffset == mi.MetadataInterval {
|
|
// the metadata generated here will be read on the next Read call
|
|
metadataBytes := mi.Metadata.Bytes()
|
|
lenByte := byte((len(metadataBytes) + 15) / 16)
|
|
mi.metadataBuf = make([]byte, int(lenByte)*16+1)
|
|
mi.metadataBuf[0] = lenByte
|
|
copy(mi.metadataBuf[1:], metadataBytes)
|
|
mi.blockOffset = 0
|
|
} else if mi.blockOffset > mi.MetadataInterval {
|
|
panic("block offset higher than metadata interval, logical error")
|
|
}
|
|
return
|
|
}
|