able to parse xml
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
package config
|
||||
|
||||
type Badger struct {
|
||||
Debug bool
|
||||
Dir string
|
||||
ValueDir *string
|
||||
Debug bool `toml:"debug"`
|
||||
Dir string `toml:"dir"`
|
||||
ValueDir *string `toml:"value_dir"`
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package config
|
||||
|
||||
type Eway struct {
|
||||
SessionID string
|
||||
SessionUser string
|
||||
Contract string
|
||||
Debug bool
|
||||
SessionID string `toml:"session_id"`
|
||||
SessionUser string `toml:"session_user"`
|
||||
OwnerID string `toml:"owner_id"`
|
||||
Debug bool `toml:"debug"`
|
||||
}
|
||||
|
||||
@ -50,6 +50,6 @@ func (l *LogFormat) UnmarshalText(data []byte) (err error) {
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
Level string `json:"level"`
|
||||
Format string `json:"format"`
|
||||
Level string `json:"level" toml:"level"`
|
||||
Format string `json:"format" toml:"format"`
|
||||
}
|
||||
|
||||
@ -45,15 +45,6 @@ type GoodsItemRaw struct {
|
||||
type MappedGoodsRemnants map[int]GoodsRemnant
|
||||
type GoodsRemnant [4]int32
|
||||
|
||||
func ExtractProductIDs(items []GoodsItem) (out []int) {
|
||||
out = make([]int, 0, len(items))
|
||||
for _, item := range items {
|
||||
out = append(out, int(item.Cart))
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func MakeGoodsItem(
|
||||
gi GoodsItemRaw,
|
||||
remnants MappedGoodsRemnants,
|
||||
|
||||
28
internal/entity/iter.go
Normal file
28
internal/entity/iter.go
Normal file
@ -0,0 +1,28 @@
|
||||
package entity
|
||||
|
||||
func IterWithErr[T any](t []T, err error) iterWithErr[T] {
|
||||
return iterWithErr[T]{
|
||||
items: t,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
type iterWithErr[T any] struct {
|
||||
items []T
|
||||
err error
|
||||
}
|
||||
|
||||
func (iter iterWithErr[T]) Do(f func(T) error) error {
|
||||
if iter.err != nil {
|
||||
return iter.err
|
||||
}
|
||||
|
||||
for _, item := range iter.items {
|
||||
err := f(item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -19,7 +19,7 @@ type Offer struct {
|
||||
PictureURLs []string `xml:"picture"`
|
||||
Vendor string `xml:"vendor"`
|
||||
Model string `xml:"model"`
|
||||
VendorCode int `xml:"vendorCode"`
|
||||
VendorCode string `xml:"vendorCode"`
|
||||
TypePrefix string `xml:"typePrefix"`
|
||||
Description string `xml:"description"`
|
||||
ManufacturerWarrany bool `xml:"manufacturer_warranty"`
|
||||
@ -33,7 +33,7 @@ type Currency struct {
|
||||
|
||||
type Category struct {
|
||||
ID int64 `xml:"id,attr"`
|
||||
ParentID int64 `xml:"parent_id,attr,omiempty"`
|
||||
ParentID int64 `xml:"parent_id,attr,omitempty"`
|
||||
Name string `xml:",chardata"`
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"encoding/xml"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
)
|
||||
@ -12,12 +13,12 @@ func TestYMLSerialize(t *testing.T) {
|
||||
faker := gofakeit.New(0)
|
||||
|
||||
categories := make([]Category, faker.Rand.Intn(4))
|
||||
knownCategory := map[int]struct{}{}
|
||||
categoryIDs := make([]int, 0, 10)
|
||||
knownCategory := map[int64]struct{}{}
|
||||
categoryIDs := make([]int64, 0, 10)
|
||||
for i := range categories {
|
||||
categories[i].ID = faker.Rand.Int()
|
||||
categories[i].ID = faker.Int64()
|
||||
categories[i].Name = faker.HipsterWord()
|
||||
categories[i].ParentID = faker.Rand.Int()
|
||||
categories[i].ParentID = faker.Int64()
|
||||
|
||||
if _, ok := knownCategory[categories[i].ID]; ok {
|
||||
continue
|
||||
@ -42,7 +43,7 @@ func TestYMLSerialize(t *testing.T) {
|
||||
}
|
||||
offer.Vendor = faker.Company()
|
||||
offer.Model = faker.CarModel()
|
||||
offer.VendorCode = faker.Rand.Int()
|
||||
offer.VendorCode = faker.DigitN(8)
|
||||
offer.TypePrefix = faker.ProductName()
|
||||
offer.Description = faker.Sentence(12)
|
||||
offer.ManufacturerWarrany = true
|
||||
@ -68,7 +69,7 @@ func TestYMLSerialize(t *testing.T) {
|
||||
Categories: categories,
|
||||
Offers: offers,
|
||||
}
|
||||
catalog.Date = faker.Date()
|
||||
catalog.Date = faker.Date().Truncate(time.Second)
|
||||
|
||||
container := YmlContainer{
|
||||
YmlCatalog: catalog,
|
||||
|
||||
@ -20,18 +20,28 @@ import (
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
GetGoodsRemnants(context.Context, []int) (entity.MappedGoodsRemnants, error)
|
||||
GetGoodsNew(
|
||||
context.Context,
|
||||
GetGoodsNewParams,
|
||||
) (items []entity.GoodsItemRaw, total int, err error)
|
||||
}
|
||||
|
||||
type client struct {
|
||||
http *resty.Client
|
||||
log zerolog.Logger
|
||||
|
||||
ownerID string
|
||||
}
|
||||
|
||||
type Config config.Eway
|
||||
|
||||
func New(cfg Config, log zerolog.Logger) client {
|
||||
if cfg.Contract == "" {
|
||||
cfg.Contract = "6101"
|
||||
func New(cfg Config, log zerolog.Logger) (client, error) {
|
||||
if cfg.SessionID == "" {
|
||||
return client{}, entity.SimpleError("no session id provided")
|
||||
}
|
||||
if cfg.SessionUser == "" {
|
||||
return client{}, entity.SimpleError("no session user provided")
|
||||
}
|
||||
|
||||
cookies := []*http.Cookie{
|
||||
@ -47,12 +57,6 @@ func New(cfg Config, log zerolog.Logger) client {
|
||||
Domain: "eway.elevel.ru",
|
||||
HttpOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "contract",
|
||||
Value: cfg.Contract,
|
||||
Domain: "eway.elevel.ru",
|
||||
HttpOnly: true,
|
||||
},
|
||||
}
|
||||
|
||||
httpclient := resty.New().
|
||||
@ -63,17 +67,11 @@ func New(cfg Config, log zerolog.Logger) client {
|
||||
return client{
|
||||
http: httpclient,
|
||||
log: log.With().Str("client", "eway").Logger(),
|
||||
}
|
||||
}
|
||||
|
||||
type getGoodsNewOrder struct {
|
||||
Column int
|
||||
Dir string
|
||||
}, nil
|
||||
}
|
||||
|
||||
type GetGoodsNewParams struct {
|
||||
Draw int
|
||||
Order getGoodsNewOrder
|
||||
Start int
|
||||
// 100 is max
|
||||
Length int
|
||||
@ -212,7 +210,7 @@ func (c client) GetGoodsNew(
|
||||
"remnants_atleast": "5",
|
||||
}).
|
||||
SetQueryParam("category_id", "0").
|
||||
SetQueryParam("own", "26476"). // user id?
|
||||
SetQueryParam("own", c.ownerID). // user id?
|
||||
SetDoNotParseResponse(true).
|
||||
Post("/goods_new")
|
||||
if err != nil {
|
||||
|
||||
@ -42,7 +42,7 @@ func (c *goodsItemClient) prefixedStr(key string) []byte {
|
||||
return c.prefixed(keyBytes)
|
||||
}
|
||||
|
||||
func (c *goodsItemClient) prefixedIDByCartStr(key int64) []byte {
|
||||
func (c *goodsItemClient) prefixedIDByCartInt64(key int64) []byte {
|
||||
var keyBytes [8]byte
|
||||
binary.BigEndian.PutUint64(keyBytes[:], uint64(key))
|
||||
return c.prefixedIDByCart(keyBytes[:])
|
||||
@ -168,22 +168,21 @@ func (c *goodsItemClient) Get(
|
||||
|
||||
func (c *goodsItemClient) GetByCart(ctx context.Context, id int64) (out entity.GoodsItem, err error) {
|
||||
err = c.db.View(func(txn *badger.Txn) error {
|
||||
var idByte [8]byte
|
||||
binary.BigEndian.PutUint64(idByte[:], uint64(id))
|
||||
|
||||
item, err := txn.Get(c.prefixedIDByCart(idByte[:]))
|
||||
idxKey := c.prefixedIDByCartInt64(id)
|
||||
skuByCartIDItem, err := txn.Get(idxKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting key: %w", err)
|
||||
}
|
||||
|
||||
sku := make([]byte, item.ValueSize())
|
||||
sku, err = item.ValueCopy(sku)
|
||||
sku := make([]byte, skuByCartIDItem.ValueSize())
|
||||
sku, err = skuByCartIDItem.ValueCopy(sku)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting value of idx: %w", err)
|
||||
}
|
||||
|
||||
// well, yeah, that's kind of dumb to trim prefix here and
|
||||
// and prefix later, but who cares.
|
||||
sku = bytes.TrimPrefix(sku, c.prefix())
|
||||
|
||||
out, err = c.getBySKU(sku, txn)
|
||||
return err
|
||||
})
|
||||
@ -206,40 +205,44 @@ func (c *goodsItemClient) upsertByBatch(ctx context.Context, items []entity.Good
|
||||
batch := c.db.NewWriteBatch()
|
||||
defer batch.Cancel()
|
||||
|
||||
log := zerolog.Ctx(ctx)
|
||||
err := func() error {
|
||||
for _, item := range items {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
break
|
||||
default:
|
||||
}
|
||||
key := c.prefixedStr(item.Articul)
|
||||
var value []byte
|
||||
if useJSON {
|
||||
value, _ = json.Marshal(item)
|
||||
} else {
|
||||
value = fbs.MakeDomainGoodItemFinished(item)
|
||||
key := c.prefixedStr(item.Articul)
|
||||
var value []byte
|
||||
if useJSON {
|
||||
value, _ = json.Marshal(item)
|
||||
} else {
|
||||
value = fbs.MakeDomainGoodItemFinished(item)
|
||||
}
|
||||
|
||||
idxValue := make([]byte, len(key))
|
||||
copy(idxValue, key)
|
||||
|
||||
coreEntry := badger.NewEntry(key, value)
|
||||
if err := batch.SetEntry(coreEntry); err != nil {
|
||||
return fmt.Errorf("setting core entry: %w", err)
|
||||
}
|
||||
|
||||
idxKey := c.prefixedIDByCartInt64(item.Cart)
|
||||
idxEntry := badger.NewEntry(idxKey, idxValue)
|
||||
if err := batch.SetEntry(idxEntry); err != nil {
|
||||
return fmt.Errorf("setting index entry: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
idxValue := make([]byte, len(key))
|
||||
copy(idxValue, key)
|
||||
|
||||
coreEntry := badger.NewEntry(key, value)
|
||||
if err := batch.SetEntry(coreEntry); err != nil {
|
||||
log.Warn().Err(err).Msg("unable to set item, breaking")
|
||||
break
|
||||
}
|
||||
|
||||
idxKey := c.prefixedIDByCartStr(item.Cart)
|
||||
idxEntry := badger.NewEntry(idxKey, idxValue)
|
||||
if err := batch.SetEntry(idxEntry); err != nil {
|
||||
log.Warn().Err(err).Msg("unable to set idx, breaking")
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
if err != nil && !errors.Is(err, context.Canceled) {
|
||||
return err
|
||||
}
|
||||
|
||||
err := batch.Flush()
|
||||
err = batch.Flush()
|
||||
if err != nil {
|
||||
return fmt.Errorf("flushing changes: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user