add encryption and get page

This commit is contained in:
Aleksandr Trushkin
2024-01-29 00:09:30 +03:00
parent c814f27c54
commit 9ef5f2bbf8
8 changed files with 436 additions and 35 deletions

View File

@ -61,7 +61,7 @@ func SetupDI(ctx context.Context, cfgpath string) error {
return nil, fmt.Errorf("getting logger: %w", err)
}
client, err := eway.New(eway.Config(cfg.Eway), log)
client, err := eway.New(ctx, eway.Config(cfg.Eway), log)
if err != nil {
return nil, fmt.Errorf("making new eway client: %w", err)
}

View File

@ -4,6 +4,7 @@ import (
"bufio"
"context"
"crypto/rand"
"encoding/binary"
"encoding/hex"
"encoding/json"
"encoding/xml"
@ -11,12 +12,15 @@ import (
"fmt"
"io"
"math/big"
"net"
"net/http"
"os"
"os/signal"
"strconv"
"time"
"git.loyso.art/frx/eway/cmd/cli/components"
"git.loyso.art/frx/eway/internal/crypto"
"git.loyso.art/frx/eway/internal/encoding/fbs"
"git.loyso.art/frx/eway/internal/entity"
"git.loyso.art/frx/eway/internal/export"
@ -101,6 +105,8 @@ func setupCLI() *cli.Command {
After: releaseDI(),
Commands: []*cli.Command{
newAppCmd(),
newCryptoCmd(),
newParseCmd(),
newImportCmd(),
newExportCmd(),
@ -111,6 +117,93 @@ func setupCLI() *cli.Command {
return app
}
func newCryptoCmd() *cli.Command {
return &cli.Command{
Name: "crypto",
Usage: "methods for encrypt/decrypt various things",
Commands: []*cli.Command{
newCryptoEncyptCmd(),
newCryptoDecryptCmd(),
},
}
}
func newCryptoEncyptCmd() *cli.Command {
return &cli.Command{
Name: "encrypt",
Usage: "encypt incoming text",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "text",
Aliases: []string{"t"},
Required: true,
},
},
Action: cryptoDeEncryptAction(true),
}
}
func newCryptoDecryptCmd() *cli.Command {
return &cli.Command{
Name: "decrypt",
Usage: "decrypt incoming text",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "text",
Aliases: []string{"t"},
Required: true,
},
},
Action: cryptoDeEncryptAction(false),
}
}
func newAppCmd() *cli.Command {
return &cli.Command{
Name: "app",
Usage: "commands for running different applications",
Commands: []*cli.Command{
newAppYmlExporter(),
},
}
}
func newAppYmlExporter() *cli.Command {
return &cli.Command{
Name: "ymlexporter",
Usage: "server on given port a http api for accessing yml catalog",
Flags: []cli.Flag{
&cli.IntFlag{
Name: "port",
Usage: "Port for accepting connections",
Value: 9448,
Validator: func(i int64) error {
if i > 1<<16 || i == 0 {
return cli.Exit("bad port value, allowed values should not exceed 65535", 1)
}
return nil
},
},
&cli.StringFlag{
Name: "src",
TakesFile: true,
Usage: "Source to catalog. Should be a valid xml file",
Value: "yml_catalog.xml",
Validator: func(s string) error {
_, err := os.Stat(s)
if err != nil {
return err
}
return nil
},
},
},
Action: appYMLExporterAction,
}
}
func newParseCmd() *cli.Command {
return &cli.Command{
Name: "parse",
@ -123,9 +216,44 @@ func newParseCmd() *cli.Command {
func newParseEwayCmd() *cli.Command {
return &cli.Command{
Name: "eway",
Usage: "parse all available eway goods",
Action: decorateAction(parseEwayAction),
Name: "eway",
Usage: "parse all available eway goods",
Commands: []*cli.Command{
newParseEwayGetCmd(),
newParseEwayDumpCmd(),
},
}
}
func newParseEwayGetCmd() *cli.Command {
return &cli.Command{
Name: "get",
Usage: "parse all available eway goods",
Flags: []cli.Flag{
&cli.IntFlag{
Name: "page",
Usage: "choose page to load",
Value: 1,
},
&cli.IntFlag{
Name: "limit",
Usage: "limits output",
Value: 100,
},
&cli.IntFlag{
Name: "min-stock",
Usage: "filters by minimum available items in stock",
},
},
Action: decorateAction(parseEwayGetAction),
}
}
func newParseEwayDumpCmd() *cli.Command {
return &cli.Command{
Name: "dump",
Usage: "dumps content of eway catalog inside db",
Action: decorateAction(parseEwayDumpAction),
}
}
@ -642,7 +770,63 @@ func exportYMLCatalogAction(ctx context.Context, c *cli.Command) error {
return enc.Encode(container)
}
func parseEwayAction(ctx context.Context, c *cli.Command) error {
func parseEwayGetAction(ctx context.Context, cmd *cli.Command) error {
page := cmd.Int("page")
limit := cmd.Int("limit")
atLeast := cmd.Int("min-stock")
searchInStocks := atLeast > 0
client, err := components.GetEwayClient()
if err != nil {
return fmt.Errorf("getting eway client: %w", err)
}
start := page * limit
items, total, err := client.GetGoodsNew(ctx, eway.GetGoodsNewParams{
Draw: 1,
Start: int(start),
Length: int(limit),
SearchInStocks: searchInStocks,
RemmantsAtleast: int(atLeast),
})
if err != nil {
return fmt.Errorf("getting new goods: %w", err)
}
productIDs := make([]int, 0, len(items))
for _, item := range items {
productIDs = append(productIDs, int(item.Cart))
}
remnants, err := client.GetGoodsRemnants(ctx, productIDs)
if err != nil {
return fmt.Errorf("getting remnants: %w", err)
}
tbl := table.New("sku", "category", "cart", "stock", "price")
for _, item := range items {
outGood, err := entity.MakeGoodsItem(item, remnants)
if err != nil {
return fmt.Errorf("making goods item: %w", err)
}
tbl.AddRow(
outGood.Articul,
outGood.Type,
outGood.Cart,
outGood.Stock,
outGood.Price,
)
}
tbl.Print()
println("total:", total)
return nil
}
func parseEwayDumpAction(ctx context.Context, cmd *cli.Command) error {
client, err := components.GetEwayClient()
if err != nil {
return fmt.Errorf("getting eway client: %w", err)
@ -833,3 +1017,104 @@ func testFBSAction(ctx context.Context, c *cli.Command) error {
return nil
}
func appYMLExporterAction(ctx context.Context, cmd *cli.Command) error {
port := cmd.Int("port")
src := cmd.String("src")
log, err := components.GetLogger()
if err != nil {
return fmt.Errorf("getting logger: %w", err)
}
mw := func(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
remoteAddr := r.RemoteAddr
xff := r.Header.Get("x-forwarded-for")
method := r.Method
ua := r.UserAgent()
xreqid := r.Header.Get("x-request-id")
if xreqid == "" {
const reqsize = 4
var reqidRaw [reqsize]byte
_, _ = rand.Read(reqidRaw[:])
value := binary.BigEndian.Uint32(reqidRaw[:])
xreqid = fmt.Sprintf("%x", value)
w.Header().Set("x-request-id", xreqid)
}
start := time.Now()
xlog := log.With().Str("request_id", xreqid).Logger()
xlog.Debug().
Str("path", path).
Str("remote_addr", remoteAddr).
Str("xff", xff).
Str("method", method).
Str("user_agent", ua).
Msg("incoming request")
xctx := xlog.WithContext(r.Context())
r = r.WithContext(xctx)
next(w, r)
elapsed := time.Since(start).Truncate(time.Millisecond).Seconds()
xlog.Info().
Float64("elapsed", elapsed).
Msg("request completed")
}
}
mux := http.NewServeMux()
mux.HandleFunc("/yml_catalog.xml", mw(func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, src)
}))
srv := &http.Server{
Addr: net.JoinHostPort("0.0.0.0", strconv.Itoa(int(port))),
Handler: mux,
}
go func() {
<-ctx.Done()
sdctx, sdcancel := context.WithTimeout(context.Background(), time.Second*5)
defer sdcancel()
errShutdown := srv.Shutdown(sdctx)
if errShutdown != nil {
log.Warn().Err(errShutdown).Msg("unable to shutdown server")
}
}()
log.Info().Str("listen_addr", srv.Addr).Msg("running server")
err = srv.ListenAndServe()
if err != nil && errors.Is(err, http.ErrServerClosed) {
return fmt.Errorf("serving http api: %w", err)
}
return nil
}
var (
someDumbKey = []byte("9530e001b619e8e98a889055f06821bb")
)
func cryptoDeEncryptAction(encrypt bool) cli.ActionFunc {
return func(ctx context.Context, c *cli.Command) (err error) {
value := c.String("text")
var out string
if encrypt {
out, err = crypto.Encrypt(value)
} else {
out, err = crypto.Decrypt(value)
}
if err != nil {
return err
}
_, err = c.Writer.Write([]byte(out))
_, err = c.Writer.Write([]byte{'\n'})
return err
}
}