3 Star 0 Fork 2

mirrors_divan/txqr

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
decode.go 3.44 KB
一键复制 编辑 原始数据 按行查看 历史
Ivan Danyliuk 提交于 2018-12-02 19:28 . Add cache to decoder
package txqr
import (
"fmt"
"math/rand"
"strings"
fountain "github.com/google/gofountain"
)
// Decoder represents protocol decode.
type Decoder struct {
chunkLen int
codec fountain.Codec
fd fountain.Decoder
completed bool
total int
cache map[string]struct{}
}
// NewDecoder creates and inits a new decoder.
func NewDecoder() *Decoder {
return &Decoder{
cache: make(map[string]struct{}),
}
}
// NewDecoderSize creates and inits a new decoder for the known size.
func NewDecoderSize(size, chunkLen int) *Decoder {
numChunks := numberOfChunks(size, chunkLen)
codec := fountain.NewLubyCodec(numChunks, rand.New(fountain.NewMersenneTwister(200)), solitonDistribution(numChunks))
return &Decoder{
codec: codec,
fd: codec.NewDecoder(size),
total: size,
chunkLen: chunkLen,
cache: make(map[string]struct{}),
}
}
// Decode takes a single chunk of data and decodes it.
// Chunk expected to be validated (see Validate) before.
func (d *Decoder) Decode(chunk string) error {
idx := strings.IndexByte(chunk, '|') // expected to be validated before
if idx == -1 {
return fmt.Errorf("invalid frame: \"%s\"", chunk)
}
header := chunk[:idx]
// continuous QR reading often sends the same chunk in a row, skip it
if d.isCached(header) {
return nil
}
var (
blockCode int64
chunkLen, total int
)
_, err := fmt.Sscanf(header, "%d/%d/%d", &blockCode, &chunkLen, &total)
if err != nil {
return fmt.Errorf("invalid header: %v (%s)", err, header)
}
payload := chunk[idx+1:]
lubyBlock := fountain.LTBlock{
BlockCode: blockCode,
Data: []byte(payload),
}
if d.fd == nil {
d.total = total
d.chunkLen = chunkLen
numChunks := numberOfChunks(d.total, d.chunkLen)
d.codec = fountain.NewLubyCodec(numChunks, rand.New(fountain.NewMersenneTwister(200)), solitonDistribution(numChunks))
d.fd = d.codec.NewDecoder(total)
}
d.completed = d.fd.AddBlocks([]fountain.LTBlock{lubyBlock})
return nil
}
// Validate checks if a given chunk of data is a valid txqr protocol packet.
func (d *Decoder) Validate(chunk string) error {
if chunk == "" || len(chunk) < 4 {
return fmt.Errorf("invalid frame: \"%s\"", chunk)
}
idx := strings.IndexByte(chunk, '|')
if idx == -1 {
return fmt.Errorf("invalid frame: \"%s\"", chunk)
}
return nil
}
// Data returns decoded data.
func (d *Decoder) Data() string {
return string(d.DataBytes())
}
// DataBytes returns decoded data as a byte slice.
func (d *Decoder) DataBytes() []byte {
if d.fd == nil {
return []byte{}
}
if !d.completed {
return []byte{}
}
return d.fd.Decode()
}
// Length returns length of the decoded data.
// TODO: remove
func (d *Decoder) Length() int {
return 0
}
// Read returns amount of currently read bytes.
// TODO: remove
func (d *Decoder) Read() int {
return 0
}
// Total returns total amount of data.
func (d *Decoder) Total() int {
return d.total
}
// IsCompleted reports whether the read was completed successfully or not.
func (d *Decoder) IsCompleted() bool {
return d.completed
}
// Reset resets decoder, preparing it for the next run.
func (d *Decoder) Reset() {
d.fd = nil
d.completed = false
d.chunkLen = 0
d.total = 0
d.cache = map[string]struct{}{}
d.codec = nil
}
// isCached takes the header of chunk data and see if it's been cached.
// If not, it caches it.
func (d *Decoder) isCached(header string) bool {
if _, ok := d.cache[header]; ok {
return true
}
// cache it
d.cache[header] = struct{}{}
return false
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/mirrors_divan/txqr.git
git@gitee.com:mirrors_divan/txqr.git
mirrors_divan
txqr
txqr
master

搜索帮助