github.com/yandex/pandora@v0.5.32/components/providers/http/decoders/decoder.go (about)

     1  package decoders
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  
    10  	"github.com/yandex/pandora/components/providers/http/config"
    11  	"github.com/yandex/pandora/components/providers/http/util"
    12  	"github.com/yandex/pandora/core"
    13  )
    14  
    15  //go:generate go run github.com/vektra/mockery/v2@v2.22.1 --inpackage --name=Decoder --filename=mock_decoder.go
    16  
    17  func filePosition(file io.ReadSeeker) (position int64) {
    18  	position, _ = file.Seek(0, io.SeekCurrent)
    19  	return
    20  }
    21  
    22  var (
    23  	ErrUnknown   = fmt.Errorf("unknown decoder faced")
    24  	ErrNoAmmo    = fmt.Errorf("no ammo in file")
    25  	ErrAmmoLimit = fmt.Errorf("ammo limit faced")
    26  	ErrPassLimit = fmt.Errorf("passes limit faced")
    27  )
    28  
    29  type Decoder interface {
    30  	Scan(context.Context) (DecodedAmmo, error)
    31  	Release(a core.Ammo)
    32  	LoadAmmo(context.Context) ([]DecodedAmmo, error)
    33  }
    34  
    35  type protoDecoder struct {
    36  	file                 io.ReadSeeker
    37  	config               config.Config
    38  	decodedConfigHeaders http.Header
    39  	ammoNum              uint // number of ammo reads
    40  	passNum              uint // number of file reads
    41  }
    42  
    43  func (d *protoDecoder) LoadAmmo(ctx context.Context, scan func(ctx context.Context) (DecodedAmmo, error)) ([]DecodedAmmo, error) {
    44  	passes := d.config.Passes
    45  	limit := d.config.Limit
    46  	d.config.Passes = 1
    47  	d.config.Limit = 0
    48  	var result []DecodedAmmo
    49  	var err error
    50  	var ammo DecodedAmmo
    51  	for err == nil {
    52  		ammo, err = scan(ctx)
    53  		if ammo != nil {
    54  			result = append(result, ammo)
    55  		}
    56  	}
    57  	d.config.Passes = passes
    58  	d.config.Limit = limit
    59  	if errors.Is(err, ErrPassLimit) {
    60  		err = nil
    61  	}
    62  
    63  	return result, err
    64  }
    65  
    66  func NewDecoder(conf config.Config, file io.ReadSeeker) (d Decoder, err error) {
    67  	decodedConfigHeaders, err := util.DecodeHTTPConfigHeaders(conf.Headers)
    68  	if err != nil {
    69  		return
    70  	}
    71  
    72  	switch conf.Decoder {
    73  	case config.DecoderJSONLine:
    74  		d, err = newJsonlineDecoder(file, conf, decodedConfigHeaders)
    75  	case config.DecoderRaw:
    76  		d = newRawDecoder(file, conf, decodedConfigHeaders)
    77  	case config.DecoderURI:
    78  		d = newURIDecoder(file, conf, decodedConfigHeaders)
    79  	case config.DecoderURIPost:
    80  		d = newURIPostDecoder(file, conf, decodedConfigHeaders)
    81  	default:
    82  		err = ErrUnknown
    83  	}
    84  	return
    85  }