From 005dbd53bcd51c0179313d89c5cb174874466d31 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Tue, 29 Nov 2022 22:42:26 +0100 Subject: [PATCH 01/17] Huge refactoring --- .env.dist | 6 +- Dockerfile | 25 -- Dockerfile.server | 30 ++ Dockerfile.worker | 29 ++ Makefile | 19 ++ deploy/image-build.sh | 29 +- deploy/image-push.sh | 7 +- .gitignore => src/.gitignore | 6 +- src/cmd/main.go | 49 ---- src/cmd/server/main.go | 72 +++++ src/cmd/worker/main.go | 155 ++++++++++ src/go.mod | 46 ++- src/go.sum | 298 +++++++++++--------- src/internal/app/config/env.go | 2 +- src/internal/app/database/connect.go | 6 +- src/internal/app/definition/basket_http.go | 9 + src/internal/app/definition/basket_model.go | 9 + src/internal/app/definition/health_http.go | 5 + src/internal/app/event/basket.go | 13 + src/internal/app/event/event.go | 12 + src/internal/app/event/order.go | 6 + src/internal/app/handler/error.go | 15 - src/internal/app/handler/handler.go | 83 ------ src/internal/app/handler/health_check.go | 40 --- src/internal/app/log.go | 16 -- src/internal/app/router.go | 22 -- src/internal/app/server.go | 85 ------ src/internal/app/server/basket_handler.go | 24 ++ src/internal/app/server/config.go | 14 + src/internal/app/server/health_handler.go | 13 + src/internal/app/server/router.go | 30 ++ src/internal/app/server/server.go | 101 +++++++ src/internal/app/service/basket.go | 51 ++++ src/pkg/amqp/connect.go | 26 ++ src/pkg/amqp/pubsub.go | 86 ++++++ src/pkg/consul/discovery.go | 107 +++++++ src/pkg/fluentd/config.go | 14 + src/pkg/fluentd/logger.go | 41 +++ 38 files changed, 1105 insertions(+), 496 deletions(-) delete mode 100644 Dockerfile create mode 100644 Dockerfile.server create mode 100644 Dockerfile.worker create mode 100644 Makefile rename .gitignore => src/.gitignore (95%) delete mode 100644 src/cmd/main.go create mode 100644 src/cmd/server/main.go create mode 100644 src/cmd/worker/main.go create mode 100644 src/internal/app/definition/basket_http.go create mode 100644 src/internal/app/definition/basket_model.go create mode 100644 src/internal/app/definition/health_http.go create mode 100644 src/internal/app/event/basket.go create mode 100644 src/internal/app/event/event.go create mode 100644 src/internal/app/event/order.go delete mode 100644 src/internal/app/handler/error.go delete mode 100644 src/internal/app/handler/handler.go delete mode 100644 src/internal/app/handler/health_check.go delete mode 100644 src/internal/app/log.go delete mode 100644 src/internal/app/router.go delete mode 100644 src/internal/app/server.go create mode 100644 src/internal/app/server/basket_handler.go create mode 100644 src/internal/app/server/config.go create mode 100644 src/internal/app/server/health_handler.go create mode 100644 src/internal/app/server/router.go create mode 100644 src/internal/app/server/server.go create mode 100644 src/internal/app/service/basket.go create mode 100644 src/pkg/amqp/connect.go create mode 100644 src/pkg/amqp/pubsub.go create mode 100644 src/pkg/consul/discovery.go create mode 100644 src/pkg/fluentd/config.go create mode 100644 src/pkg/fluentd/logger.go diff --git a/.env.dist b/.env.dist index e8fd4ed..84c5d45 100644 --- a/.env.dist +++ b/.env.dist @@ -1,2 +1,4 @@ -SERVER_IP=0.0.0.0 -DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/egommerce +SERVER_ADDR=:80 +DATABASE_URL=postgres://postgres:12345678@postgres-db:5432/egommerce +MONGODB_URL=mongodb://mongodb:12345678@mongo-db:27017 +EVENTBUS_URL=amqp://guest:guest@api-eventbus:5672 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 42da419..0000000 --- a/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -# Builder -FROM golang:alpine AS builder - -WORKDIR /go/src/app - -ARG MAIN_GO=cmd/main.go - -COPY src ./ - -RUN go mod download && \ - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/app $MAIN_GO - -# Destination image -FROM gcr.io/distroless/base-debian10 - -LABEL author="Piotr Biernat" -LABEL service="basket" -LABEL vendor="Egommerce" -LABEL version="1.0" - -COPY --from=builder /go/bin/app /app -COPY .env.dist /.env - -EXPOSE 8080 -ENTRYPOINT ["/app"] diff --git a/Dockerfile.server b/Dockerfile.server new file mode 100644 index 0000000..00c5cb8 --- /dev/null +++ b/Dockerfile.server @@ -0,0 +1,30 @@ +# Builder +FROM golang:alpine AS builder + +ARG BIN_OUTPUT=/go/bin/server +ARG GO_MAIN=cmd/server/main.go + +WORKDIR /go/src/app +COPY src ./ + +RUN go mod download && \ + export CGO_ENABLED=0 ; export GOOS=linux ; export GOARCH=amd64 && \ + go build -ldflags="-w -s" -o $BIN_OUTPUT $GO_MAIN + + +# Destination image - server +FROM gcr.io/distroless/base-debian10 + +ARG BIN_OUTPUT=/go/bin/server + +LABEL author="Piotr Biernat" +LABEL service="basket-svc" +LABEL vendor="Egommerce" +LABEL version="1.0" + +WORKDIR / +COPY --from=builder $BIN_OUTPUT / +COPY .env.dist /.env + +EXPOSE 80 +ENTRYPOINT ["/server"] diff --git a/Dockerfile.worker b/Dockerfile.worker new file mode 100644 index 0000000..d2fc1e2 --- /dev/null +++ b/Dockerfile.worker @@ -0,0 +1,29 @@ +# Builder +FROM golang:alpine AS builder + +ARG BIN_OUTPUT=/go/bin/worker +ARG GO_WORKER=cmd/worker/main.go + +WORKDIR /go/src/app +COPY src ./ + +RUN go mod download && \ + export CGO_ENABLED=0 ; export GOOS=linux ; export GOARCH=amd64 && \ + go build -ldflags="-w -s" -o $BIN_OUTPUT $GO_WORKER + + +# Destination image - worker +FROM gcr.io/distroless/base-debian10 + +ARG BIN_OUTPUT=/go/bin/worker + +LABEL author="Piotr Biernat" +LABEL service="basket-worker" +LABEL vendor="Egommerce" +LABEL version="1.0" + +WORKDIR / +COPY --from=builder $BIN_OUTPUT / +COPY .env.dist /.env + +ENTRYPOINT ["/worker"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2d234f9 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +DEPLOY_DIR := ./deploy +SRC_DIR := ./src + +## DEPLOY PART +build-image-dev: + - sh ${DEPLOY_DIR}/image-build.sh dev + +build-image-prod: + - sh ${DEPLOY_DIR}/image-build.sh + +push-image-prod: + - sh ${DEPLOY_DIR}/image-push.sh + +# (GOLANG) APP PART +app-run: + - make -C ${SRC_DIR} run + +app-build: + - make -C ${SRC_DIR} build diff --git a/deploy/image-build.sh b/deploy/image-build.sh index a3a4ce1..e918399 100755 --- a/deploy/image-build.sh +++ b/deploy/image-build.sh @@ -1,6 +1,31 @@ #!/bin/sh # RUN IN REPO ROOT DIR !! -export IMAGE_NAME="git.pbiernat.dev/egommerce/basket-svc" +export IMAGE_BASE="git.pbiernat.dev/egommerce/basket" +export SERVER_IMAGE="$IMAGE_BASE-svc" +export WORKER_IMAGE="$IMAGE_BASE-worker" -docker build --rm --cache-from "$IMAGE_NAME:latest" -t "$IMAGE_NAME:latest" . +TARGET=${1:-latest} +KIND=${2:-all} + +if [ $KIND = "svc" ] || [ $KIND = "all" ]; then + echo "Building: $SERVER_IMAGE:$TARGET" + if [ $TARGET = "dev" ] + then + docker build --rm --no-cache -t "$SERVER_IMAGE:$TARGET" -f Dockerfile.server . # >/dev/null 2>&1 + else + docker build --rm --cache-from "$SERVER_IMAGE:$TARGET" -t "$SERVER_IMAGE:$TARGET" -f Dockerfile.server . >/dev/null 2>&1 + fi +fi + +if [ $KIND = "worker" ] || [ $KIND = "all" ]; then + echo "Building: $WORKER_IMAGE:$TARGET" + if [ $TARGET = "dev" ] + then + docker build --rm --no-cache -t "$WORKER_IMAGE:$TARGET" -f Dockerfile.worker . # >/dev/null 2>&1 + else + docker build --rm --cache-from "$WORKER_IMAGE:$TARGET" -t "$WORKER_IMAGE:$TARGET" -f Dockerfile.worker . >/dev/null 2>&1 + fi +fi + +echo "Done." diff --git a/deploy/image-push.sh b/deploy/image-push.sh index 5debde1..dd8e644 100755 --- a/deploy/image-push.sh +++ b/deploy/image-push.sh @@ -1,7 +1,10 @@ #!/bin/sh # RUN IN REPO ROOT DIR !! -export IMAGE_NAME="git.pbiernat.dev/egommerce/basket-svc" +export IMAGE_BASE="git.pbiernat.dev/egommerce/basket" +export SERVER_IMAGE="$IMAGE_BASE-svc" +export WORKER_IMAGE="$IMAGE_BASE-worker" echo $DOCKER_PASSWORD | docker login git.pbiernat.dev -u $DOCKER_USERNAME --password-stdin -docker push "$IMAGE_NAME:latest" +docker push "$SERVER_IMAGE:latest" +docker push "$WORKER_IMAGE:latest" diff --git a/.gitignore b/src/.gitignore similarity index 95% rename from .gitignore rename to src/.gitignore index 5f0d744..47de0bc 100644 --- a/.gitignore +++ b/src/.gitignore @@ -12,8 +12,6 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out -# Dependency directories (remove the comment below to include it) -# vendor/ - .env - +# Dependency directories (remove the comment below to include it) +vendor/ diff --git a/src/cmd/main.go b/src/cmd/main.go deleted file mode 100644 index 049e3ab..0000000 --- a/src/cmd/main.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "context" - "net" - "os" - "os/signal" - "time" - - "git.pbiernat.dev/egommerce/basket-service/internal/app" - "git.pbiernat.dev/egommerce/basket-service/internal/app/config" - "git.pbiernat.dev/egommerce/basket-service/internal/app/database" - "git.pbiernat.dev/egommerce/basket-service/internal/app/handler" -) - -const ( - defHTTPIP = "0.0.0.0" - defHTTPPort = "8080" - defDbURL = "postgres://postgres:12345678@127.0.0.1:5432/egommerce" -) - -func main() { - if config.ErrLoadingEnvs != nil { - app.Panicf("Error loading .env file") - } - - httpAddr := net.JoinHostPort(config.GetEnv("SERVER_IP", defHTTPIP), defHTTPPort) - dbConnStr := config.GetEnv("DATABASE_URL", defDbURL) - - dbc, err := database.Connect(dbConnStr) - if err != nil { - app.Panicf("Unable to connect to database: %v\n", err) - } - - env := &handler.Env{Addr: httpAddr, DB: dbc} - srv := app.NewServer(env) - - go srv.Start() - - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt) - <-c - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - - srv.Shutdown(ctx) - os.Exit(0) -} diff --git a/src/cmd/server/main.go b/src/cmd/server/main.go new file mode 100644 index 0000000..d17af5c --- /dev/null +++ b/src/cmd/server/main.go @@ -0,0 +1,72 @@ +package main + +import ( + "log" + "os" + "strconv" + + "git.pbiernat.dev/egommerce/basket-service/internal/app/config" + "git.pbiernat.dev/egommerce/basket-service/internal/app/database" + "git.pbiernat.dev/egommerce/basket-service/internal/app/server" + "git.pbiernat.dev/egommerce/basket-service/pkg/amqp" + "git.pbiernat.dev/egommerce/basket-service/pkg/fluentd" +) + +const ( + defAppName = "basket-svc" + defAppDomain = "basket-svc" + defNetAddr = ":80" + defLoggerAddr = "api-logger:24224" + defDbURL = "postgres://postgres:12345678@postgres-db:5432/egommerce" + defMongoDbURL = "mongodb://mongodb:12345678@mongo-db:27017" + defEventBusURL = "amqp://guest:guest@api-eventbus:5672" + ebEventsExchange = "api-events" + ebEventsQueue = "basket-svc" +) + +func main() { + if config.ErrLoadingEnvs != nil { + log.Panicln("Error loading .env file", config.ErrLoadingEnvs) + } + + c := new(server.Config) + c.AppName = config.GetEnv("APP_NAME", defAppName) + c.AppDomain = config.GetEnv("APP_DOMAIN", defAppDomain) + c.NetAddr = config.GetEnv("SERVER_ADDR", defNetAddr) + c.Port, _ = strconv.Atoi(c.NetAddr[1:]) + c.LoggerAddr = config.GetEnv("LOGGER_ADDR", defLoggerAddr) + c.DbURL = config.GetEnv("DATABASE_URL", defDbURL) + c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) + c.EventBusExchange = ebEventsExchange + + logHost, logPort := fluentd.ParseAddr(c.LoggerAddr) + logger := fluentd.NewLogger(c.AppName, logHost, logPort) + defer logger.Close() + + // db conn + dbConn, err := database.Connect(c.DbURL) + if err != nil { // fixme: add wait-for-db... + logger.Log("Failed to connect to Database server: %v\n", err) + os.Exit(1) + } + defer dbConn.Close() + + // eventbus conn + ebConn, ebCh, err := amqp.Open(c.EventBusURL) + if err != nil { + logger.Log("Failed to connect to EventBus server: %v\n", err) + os.Exit(1) + } + defer ebCh.Close() + defer amqp.Close(ebConn) + + err = amqp.NewExchange(ebCh, c.EventBusExchange) + if err != nil { + logger.Log("Failed to declare EventBus exchange: %v\n", err) + os.Exit(1) + } + + // start server + srv := server.NewServer(c, logger, dbConn, ebCh) + srv.StartWithGracefulShutdown() +} diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go new file mode 100644 index 0000000..b23620e --- /dev/null +++ b/src/cmd/worker/main.go @@ -0,0 +1,155 @@ +package main + +import ( + "fmt" + "log" + "os" + "strings" + + "git.pbiernat.dev/egommerce/basket-service/internal/app/config" + "git.pbiernat.dev/egommerce/basket-service/internal/app/database" + "git.pbiernat.dev/egommerce/basket-service/internal/app/server" + "git.pbiernat.dev/egommerce/basket-service/internal/app/service" + "git.pbiernat.dev/egommerce/basket-service/pkg/amqp" + "git.pbiernat.dev/egommerce/basket-service/pkg/fluentd" + "github.com/google/uuid" +) + +const ( + defAppName = "basket-worker" + defLoggerAddr = "api-logger:24224" + defDbURL = "postgres://postgres:12345678@postgres-db:5432/egommerce" + defMongoDbURL = "mongodb://mongodb:12345678@mongo-db:27017" + defEventBusURL = "amqp://guest:guest@api-eventbus:5672" + ebEventsExchange = "api-events" + ebEventsQueue = "basket-worker" +) + +func main() { + if config.ErrLoadingEnvs != nil { + log.Panicln("Error loading .env file", config.ErrLoadingEnvs) + } + + id := uuid.New().String()[24:] + c := new(server.Config) + c.AppName = config.GetEnv("APP_NAME", defAppName) + "#:" + id + c.LoggerAddr = config.GetEnv("LOGGER_ADDR", defLoggerAddr) + c.DbURL = config.GetEnv("DATABASE_URL", defDbURL) + c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) + c.EventBusExchange = ebEventsExchange + c.EventBusQueue = ebEventsQueue + // c.EventBusQueue = fmt.Sprintf("%s-%s", ebEventsQueue, id) + + logHost, logPort := fluentd.ParseAddr(c.LoggerAddr) + logger := fluentd.NewLogger(c.AppName, logHost, logPort) + defer logger.Close() + + // db conn + dbConn, err := database.Connect(c.DbURL) + if err != nil { // fixme: add wait-for-db... + logger.Log("Failed to connect to Database server: %v\n", err) + os.Exit(1) + } + defer dbConn.Close() + + // eventbus conn + ebConn, ebCh, err := amqp.Open(c.EventBusURL) + if err != nil { + logger.Log("Failed to connect to EventBus server: %v\n", err) + os.Exit(1) + } + defer ebCh.Close() + defer amqp.Close(ebConn) + + err = amqp.NewExchange(ebCh, c.EventBusExchange) + if err != nil { + logger.Log("Failed to declare EventBus exchange: %v\n", err) + os.Exit(1) + } + + // create and bind queues + _, err = ebCh.QueueDeclare( + c.EventBusQueue, // name + false, // durable + false, // delete when unused + false, // exclusive + false, // no-wait + nil, // arguments + ) + if err != nil { + logger.Log("Failed to declare EventBus queue: %v\n", err) + os.Exit(1) + } + + amqp.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "catalog.basket.productAddedToBasket") + amqp.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "catalog.basket.productRemovedFromBasket") + amqp.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "catalog.basket.updateQuantity") + // err = amqp.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "catalog-svc.product.addedToBasket") + // if err != nil { + // logger.Log("Failed to prepare EventBus queue: %v\n", err) + // os.Exit(1) + // } + + msgs, err := ebCh.Consume( + c.EventBusQueue, // queue + "", // consumer + false, // auto-ack + false, // exclusive + false, // no-local + false, // no-wait + nil, // args + ) + if err != nil { + logger.Log("Failed to register a consumer: %s", err) + os.Exit(1) + } + + var forever chan struct{} + go func() { + basket := service.NewBasketService(dbConn, ebCh, logger) + + for d := range msgs { + msg, err := amqp.Deserialize(d.Body) + if err != nil { + logger.Log("json error:", err) + d.Reject(false) // FIXME: how to handle erros in queue...???? + continue + } + + event := fmt.Sprintf("%s", msg["event"]) + data := (msg["data"]).(map[string]interface{}) + logger.Log("Message<%s>: %#v", event, data) + + basketID := data["basket_id"].(string) // FIXME CHECK basket_id!!! + + switch true { + case strings.Contains(event, amqp.EVENT_PRODUCT_ADDED_TO_BASKET): + // create new basket and add product to it + // FIXME CHECK if basket exists + _, err := basket.Get(basketID) + if err != nil { + logger.Log("Basket#%s not found. Creating...", basketID) + err := basket.Create(basketID) + if err != nil { + logger.Log("Creating basket error: %s", err) + d.Reject(false) + continue + } + } + + case strings.Contains(event, amqp.EVENT_PRODUCT_REMOVED_FROM_BASKET): + // remove product from basket + } + logger.Log("ACK: %s", event) + d.Ack(false) + } + }() + + logger.Log("Waiting for messages...") + <-forever +} + +// create basket if not exists, next update product quantity +func updateBasketState() { + +} diff --git a/src/go.mod b/src/go.mod index 8020b13..15331d1 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,21 +3,45 @@ module git.pbiernat.dev/egommerce/basket-service go 1.18 require ( - github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/gorilla/mux v1.8.0 - github.com/jackc/pgx/v4 v4.17.2 + github.com/fluent/fluent-logger-golang v1.9.0 + github.com/gofiber/fiber/v2 v2.40.1 + github.com/google/uuid v1.3.0 + github.com/hashicorp/consul/api v1.17.0 + github.com/jackc/pgx/v5 v5.1.1 github.com/joho/godotenv v1.4.0 + github.com/streadway/amqp v1.0.0 ) require ( - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.13.0 // indirect - github.com/jackc/pgio v1.0.0 // indirect + github.com/andybalholm/brotli v1.0.4 // indirect + github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect + github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect + github.com/fatih/color v1.9.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.1 // indirect + github.com/hashicorp/go-hclog v0.12.0 // indirect + github.com/hashicorp/go-immutable-radix v1.0.0 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/serf v0.10.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect - github.com/jackc/puddle v1.3.0 // indirect - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect - golang.org/x/text v0.3.7 // indirect + github.com/jackc/puddle/v2 v2.1.2 // indirect + github.com/klauspost/compress v1.15.9 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/philhofer/fwd v1.1.1 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/tinylib/msgp v1.1.6 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.41.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect + golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect + golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect + golang.org/x/text v0.3.8 // indirect ) diff --git a/src/go.sum b/src/go.sum index c09ba18..28db6c8 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,190 +1,216 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fluent/fluent-logger-golang v1.9.0 h1:zUdY44CHX2oIUc7VTNZc+4m+ORuO/mldQDA7czhWXEg= +github.com/fluent/fluent-logger-golang v1.9.0/go.mod h1:2/HCT/jTy78yGyeNGQLGQsjF3zzzAuy6Xlk6FCMV5eU= +github.com/gofiber/fiber/v2 v2.40.1 h1:pc7n9VVpGIqNsvg9IPLQhyFEMJL8gCs1kneH5D1pIl4= +github.com/gofiber/fiber/v2 v2.40.1/go.mod h1:Gko04sLksnHbzLSRBFWPFdzM9Ws9pRxvvIaohJK1dsk= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/consul/api v1.17.0 h1:aqytbw31uCPNn37ST+717IyGod+P1eTgSGu3yjRo4bs= +github.com/hashicorp/consul/api v1.17.0/go.mod h1:ZNwemOPAdgtV4cCx9fqxNmw+PI3vliW6gYin2WD+F2g= +github.com/hashicorp/consul/sdk v0.13.0 h1:lce3nFlpv8humJL8rNrrGHYSKc3q+Kxfeg3Ii1m6ZWU= +github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= +github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= +github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/pgx/v5 v5.1.1 h1:pZD79K1SYv8wc2HmCQA6VdmRQi7/OtCfv9bM3WAXUYA= +github.com/jackc/pgx/v5 v5.1.1/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk= +github.com/jackc/puddle/v2 v2.1.2 h1:0f7vaaXINONKTsxYDn4otOAiJanX/BMeAtY//BXqzlg= +github.com/jackc/puddle/v2 v2.1.2/go.mod h1:2lpufsF5mRHO6SuZkm0fNYxM6SWHfvyFj62KwNzgels= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ= +github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= +github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +github.com/tinylib/msgp v1.1.6 h1:i+SbKraHhnrf9M5MYmvQhFnbLhAXSDWF8WWsuyRdocw= +github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.41.0 h1:zeR0Z1my1wDHTRiamBCXVglQdbUwgb9uWG3k1HQz6jY= +github.com/valyala/fasthttp v1.41.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc= +golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/src/internal/app/config/env.go b/src/internal/app/config/env.go index f08d8ff..9dbe349 100644 --- a/src/internal/app/config/env.go +++ b/src/internal/app/config/env.go @@ -12,7 +12,7 @@ func init() { ErrLoadingEnvs = godotenv.Load() } -func GetEnv(name, defVal string) string { +func GetEnv(name string, defVal string) string { // FIXME defVal and return types env := os.Getenv(name) if env == "" { return defVal diff --git a/src/internal/app/database/connect.go b/src/internal/app/database/connect.go index b44cfdd..e8c889c 100644 --- a/src/internal/app/database/connect.go +++ b/src/internal/app/database/connect.go @@ -3,14 +3,14 @@ package database import ( "context" - "github.com/jackc/pgx/v4/pgxpool" + "github.com/jackc/pgx/v5/pgxpool" ) func Connect(connStr string) (*pgxpool.Pool, error) { - conn, err := pgxpool.Connect(context.Background(), connStr) + pool, err := pgxpool.New(context.Background(), connStr) if err != nil { return nil, err } - return conn, nil + return pool, nil } diff --git a/src/internal/app/definition/basket_http.go b/src/internal/app/definition/basket_http.go new file mode 100644 index 0000000..001c4dc --- /dev/null +++ b/src/internal/app/definition/basket_http.go @@ -0,0 +1,9 @@ +package definition + +type BasketCheckoutRequest struct { + BasketID string `json:"basket_id"` +} + +type BasketCheckoutResponse struct { + ID string `json:"order_id"` +} diff --git a/src/internal/app/definition/basket_model.go b/src/internal/app/definition/basket_model.go new file mode 100644 index 0000000..a477aca --- /dev/null +++ b/src/internal/app/definition/basket_model.go @@ -0,0 +1,9 @@ +package definition + +import "time" + +type Basket struct { + ID string `db:"id"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` +} diff --git a/src/internal/app/definition/health_http.go b/src/internal/app/definition/health_http.go new file mode 100644 index 0000000..6920fca --- /dev/null +++ b/src/internal/app/definition/health_http.go @@ -0,0 +1,5 @@ +package definition + +type HealthResponse struct { + Status string `json:"status,omitempty"` +} diff --git a/src/internal/app/event/basket.go b/src/internal/app/event/basket.go new file mode 100644 index 0000000..0e8f578 --- /dev/null +++ b/src/internal/app/event/basket.go @@ -0,0 +1,13 @@ +package event + +type ProductAddedToBasketEvent struct { + *Event + ProductID string `json:"product_id"` + BasketID string `json:"basket_id"` +} + +type ProductRemovedFromBasketEvent struct { + *Event + ProductID string `json:"product_id"` + BasketID string `json:"basket_id"` +} diff --git a/src/internal/app/event/event.go b/src/internal/app/event/event.go new file mode 100644 index 0000000..3dd7a42 --- /dev/null +++ b/src/internal/app/event/event.go @@ -0,0 +1,12 @@ +package event + +type Event struct { + RequestID string `json:"request_id"` +} + +func NewEvent(reqID string) *Event { + em := new(Event) + em.RequestID = reqID + + return em +} diff --git a/src/internal/app/event/order.go b/src/internal/app/event/order.go new file mode 100644 index 0000000..e5cad99 --- /dev/null +++ b/src/internal/app/event/order.go @@ -0,0 +1,6 @@ +package event + +type BasketCheckoutEvent struct { + *Event + BasketID string `json:"basket_id"` +} diff --git a/src/internal/app/handler/error.go b/src/internal/app/handler/error.go deleted file mode 100644 index 540b989..0000000 --- a/src/internal/app/handler/error.go +++ /dev/null @@ -1,15 +0,0 @@ -package handler - -import "net/http" - -type NotFoundHandler struct{} - -func (NotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - encodeResponse(w, &response{http.StatusNotFound, "Path " + r.RequestURI + " not found"}, nil) -} - -type MethodNotAllowedHandler struct{} - -func (MethodNotAllowedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - encodeResponse(w, &response{http.StatusMethodNotAllowed, "Method Not Allowed: " + r.Method}, nil) -} diff --git a/src/internal/app/handler/handler.go b/src/internal/app/handler/handler.go deleted file mode 100644 index 0f76908..0000000 --- a/src/internal/app/handler/handler.go +++ /dev/null @@ -1,83 +0,0 @@ -package handler - -import ( - "bytes" - "encoding/json" - "io" - "log" - "net/http" - - def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" - "github.com/gorilla/mux" - "github.com/jackc/pgx/v4/pgxpool" -) - -type Env struct { - Addr string - DB *pgxpool.Pool -} - -type Handler struct { - *Env - Handle HandlerFunc - Request interface{} - Response interface{} - Params Set -} - -type HandlerFunc func(h *Handler, w http.ResponseWriter) (interface{}, int, error) - -type Set map[string]string - -type response struct { - Status int - Data interface{} -} - -func Init(e *Env, h *Handler) *Handler { - // return &Handler{e, h.Handle, h.Request, h.Response, Set{}} - h.Env = e - - return h -} - -func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if err := decodeRequestData(r, h.Request); err != nil { - log.Println("Decode request data error:", err.Error()) - - w.WriteHeader(http.StatusInternalServerError) - } - - h.Params = mux.Vars(r) - res, code, err := h.Handle(h, w) - - encodeResponse(w, &response{code, res}, err) -} - -func decodeRequestData(r *http.Request, v interface{}) error { - buf, _ := io.ReadAll(r.Body) - rdr := io.NopCloser(bytes.NewReader(buf)) - r.Body = io.NopCloser(bytes.NewReader(buf)) - - json.NewDecoder(rdr).Decode(&v) - - return nil -} - -func encodeResponse(w http.ResponseWriter, res *response, err error) { - if err != nil { - encodeError(w, res.Status, err) - return - } - - w.WriteHeader(res.Status) - if res.Data != nil { - json.NewEncoder(w).Encode(res.Data) - } -} - -func encodeError(w http.ResponseWriter, status int, e error) { - w.WriteHeader(status) - - json.NewEncoder(w).Encode(def.Error(e.Error())) -} diff --git a/src/internal/app/handler/health_check.go b/src/internal/app/handler/health_check.go deleted file mode 100644 index 6681dc9..0000000 --- a/src/internal/app/handler/health_check.go +++ /dev/null @@ -1,40 +0,0 @@ -package handler - -import ( - "net/http" -) - -var HealthCheckHandler *Handler - -func init() { - HealthCheckHandler = &Handler{ - Handle: HealthCheckHandlerFunc, - Request: &HealthCheckRequest{}, - Response: &HealthCheckResponse{}, - } -} - -type HealthCheckRequest struct { -} - -type HealthCheckResponse struct { - Status string `json:"status"` - Data *HealthCheckResponseBody `json:"data"` -} - -type HealthCheckResponseBody struct { - Message string `json:"message,omitempty"` -} - -func HealthCheckHandlerFunc(_ *Handler, w http.ResponseWriter) (interface{}, int, error) { - return &HealthCheckResponseBody{ - Message: "This is welcome health message. Everything seems to be alright ;)", - }, http.StatusOK, nil - - // return &HealthCheckResponse{ - // Status: http.StatusText(http.StatusOK), - // Data: &HealthCheckResponseBody{ - // Message: "This is welcome health message. Everything seems to be alright ;)", - // }, - // }, http.StatusOK, nil -} diff --git a/src/internal/app/log.go b/src/internal/app/log.go deleted file mode 100644 index 53fe9c1..0000000 --- a/src/internal/app/log.go +++ /dev/null @@ -1,16 +0,0 @@ -package app - -import "log" - -func Panic(v ...any) { - log.Panicln(Name + ":", v) -} - -func Panicf(format string, v ...any) { - log.Panicf(Name + ": " + format, v...) -} - -func Panicln(v ...any) { - v = append([]any{Name + ":"}, v...) - log.Panicln(v...) -} \ No newline at end of file diff --git a/src/internal/app/router.go b/src/internal/app/router.go deleted file mode 100644 index daf9eea..0000000 --- a/src/internal/app/router.go +++ /dev/null @@ -1,22 +0,0 @@ -package app - -import ( - "net/http" - - "git.pbiernat.dev/egommerce/basket-service/internal/app/handler" - "github.com/gorilla/mux" -) - -func SetupRouter(env *handler.Env) *mux.Router { - r := mux.NewRouter() - r.NotFoundHandler = &handler.NotFoundHandler{} - r.MethodNotAllowedHandler = &handler.MethodNotAllowedHandler{} - - r.Use(PrepareHeadersMiddleware) - r.Use(ValidateJSONBodyMiddleware) // probably not needed - r.Use(LoggingMiddleware) - - r.Handle("/health", handler.Init(env, handler.HealthCheckHandler)).Methods(http.MethodGet) - - return r -} diff --git a/src/internal/app/server.go b/src/internal/app/server.go deleted file mode 100644 index b7a114f..0000000 --- a/src/internal/app/server.go +++ /dev/null @@ -1,85 +0,0 @@ -package app - -import ( - "bytes" - "encoding/json" - "io" - "log" - "net" - "net/http" - "os" - "strconv" - "time" - - def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" - "git.pbiernat.dev/egommerce/basket-service/internal/app/handler" -) - -const Name = "REST API Service" - -type Server struct { - *http.Server -} - -func NewServer(env *handler.Env) *Server { - return &Server{ - &http.Server{ - Handler: SetupRouter(env), - Addr: env.Addr, - WriteTimeout: 15 * time.Second, - ReadTimeout: 15 * time.Second, - IdleTimeout: 60 * time.Second, - }, - } -} - -func (s *Server) Start() { - if os.Getenv("LISTEN_PID") == strconv.Itoa(os.Getpid()) { - // systemd run - f := os.NewFile(3, "from systemd") - l, err := net.FileListener(f) - if err != nil { - log.Fatalln(err) - } - - log.Println("Server listening on " + l.Addr().String()) - s.Serve(l) - } else { - - log.Println("Server listening on " + s.Addr) - log.Fatalln(s.ListenAndServe()) - } -} - -func PrepareHeadersMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.Header().Set("Connection", "keep-alive") - w.Header().Set("Keep-Alive", "timeout=5") - - next.ServeHTTP(w, r) - }) -} - -func ValidateJSONBodyMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - buf, _ := io.ReadAll(r.Body) - r.Body = io.NopCloser(bytes.NewReader(buf)) // rollack *Request to original state - - if len(buf) > 0 && !json.Valid(buf) { - w.WriteHeader(http.StatusBadRequest) - json.NewEncoder(w).Encode(def.Error("Unable to parse JSON: " + string(buf))) - - return - } - - next.ServeHTTP(w, r) - }) -} - -func LoggingMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Println("Request: " + r.RequestURI + " remote: " + r.RemoteAddr + " via: " + r.UserAgent()) - next.ServeHTTP(w, r) - }) -} diff --git a/src/internal/app/server/basket_handler.go b/src/internal/app/server/basket_handler.go new file mode 100644 index 0000000..078bb7a --- /dev/null +++ b/src/internal/app/server/basket_handler.go @@ -0,0 +1,24 @@ +package server + +import ( + def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" + "git.pbiernat.dev/egommerce/basket-service/internal/app/service" + "github.com/gofiber/fiber/v2" +) + +func (s *Server) CheckoutHandler(c *fiber.Ctx) error { + reqID, _ := s.GetRequestID(c) + data := new(def.BasketCheckoutRequest) + if err := c.BodyParser(data); err != nil { + return err + } + + basketID := data.BasketID + // vlaidate, pre check... etc + basket := service.NewBasketService(s.dbConn, s.ebCh, s.log) + basket.Checkout(reqID, basketID) + + return c.JSON(&def.BasketCheckoutResponse{ + ID: data.BasketID, + }) +} diff --git a/src/internal/app/server/config.go b/src/internal/app/server/config.go new file mode 100644 index 0000000..9d81e64 --- /dev/null +++ b/src/internal/app/server/config.go @@ -0,0 +1,14 @@ +package server + +type Config struct { + AppName string + AppDomain string + NetAddr string + Port int + LoggerAddr string + DbURL string + MongoDbUrl string + EventBusURL string + EventBusExchange string + EventBusQueue string +} diff --git a/src/internal/app/server/health_handler.go b/src/internal/app/server/health_handler.go new file mode 100644 index 0000000..9ec6016 --- /dev/null +++ b/src/internal/app/server/health_handler.go @@ -0,0 +1,13 @@ +package server + +import ( + "github.com/gofiber/fiber/v2" + + def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" +) + +func (s *Server) HealthHandler(c *fiber.Ctx) error { + return c.JSON(&def.HealthResponse{ + Status: "OK", + }) +} diff --git a/src/internal/app/server/router.go b/src/internal/app/server/router.go new file mode 100644 index 0000000..0409125 --- /dev/null +++ b/src/internal/app/server/router.go @@ -0,0 +1,30 @@ +package server + +import ( + "git.pbiernat.dev/egommerce/basket-service/pkg/fluentd" + "github.com/gofiber/fiber/v2" +) + +func SetupRoutes(s *Server) { + api := s.App.Group("/api") + v1 := api.Group("/v1") + v1.Post("/checkout", s.CheckoutHandler) + + s.App.Get("/health", s.HealthHandler) +} + +func SetupMiddlewares(s *Server) { + s.App.Use(LoggingMiddleware(s.log)) +} + +// Middlewares +func LoggingMiddleware(log *fluentd.Logger) func(c *fiber.Ctx) error { + return func(c *fiber.Ctx) error { + log.Log("Request: %s, remote: %s, via: %s", + c.Request().URI().String(), + c.Context().RemoteIP().String(), + string(c.Context().UserAgent())) + + return c.Next() + } +} diff --git a/src/internal/app/server/server.go b/src/internal/app/server/server.go new file mode 100644 index 0000000..3e39ae7 --- /dev/null +++ b/src/internal/app/server/server.go @@ -0,0 +1,101 @@ +package server + +import ( + "os" + "os/signal" + "time" + + "github.com/gofiber/fiber/v2" + "github.com/jackc/pgx/v5/pgxpool" + "github.com/streadway/amqp" + + discovery "git.pbiernat.dev/egommerce/basket-service/pkg/consul" + "git.pbiernat.dev/egommerce/basket-service/pkg/fluentd" +) + +type Server struct { + *fiber.App + log *fluentd.Logger + dbConn *pgxpool.Pool + ebCh *amqp.Channel + name string + addr string +} + +type RequestID struct { + RequestID string `reqHeader:"x-request-id"` +} + +func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amqp.Channel) *Server { + discovery, err := discovery.NewService(conf.AppName, conf.AppDomain, conf.Port) + if err != nil { + logger.Log("Error connecting to api-registry: %v", err) + } + + logger.Log("Registering service with name: %s, address: %s", discovery.Name, discovery.Address) + err = discovery.Register() + if err != nil { + logger.Log(err.Error()) + } + + cnf := fiber.Config{ + AppName: conf.AppName, + ServerHeader: conf.AppDomain, + ReadTimeout: time.Millisecond * 50, + WriteTimeout: time.Millisecond * 50, + IdleTimeout: time.Millisecond * 50, + } + s := &Server{ + fiber.New(cnf), + logger, + db, + ebCh, + conf.AppName, + conf.NetAddr, + } + + SetupMiddlewares(s) + SetupRoutes(s) + + return s +} + +func (s *Server) Start() { + err := s.Listen(s.addr) + s.log.Log("Starting error: %v", err) +} + +func (s *Server) StartWithGracefulShutdown() { + idle := make(chan struct{}) + + go func() { + sigint := make(chan os.Signal, 1) + signal.Notify(sigint, os.Interrupt) + <-sigint + + if err := s.Shutdown(); err != nil { + s.log.Log("Server is not shutting down! Reason: %v", err) + } + + s.log.Log("Servier is going down...") + // remove info from registry and close all connection here... + + close(idle) + }() + + if err := s.Listen(s.addr); err != nil { + s.log.Log("Server is not running! Reason: %v", err) + } + + <-idle +} + +func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) { + var hdr = new(RequestID) + if err := c.ReqHeaderParser(hdr); err != nil { + return "", err + } + + return hdr.RequestID, nil + +} diff --git a/src/internal/app/service/basket.go b/src/internal/app/service/basket.go new file mode 100644 index 0000000..2973f67 --- /dev/null +++ b/src/internal/app/service/basket.go @@ -0,0 +1,51 @@ +package service + +import ( + "context" + + "git.pbiernat.dev/egommerce/basket-service/internal/app/event" + "git.pbiernat.dev/egommerce/basket-service/pkg/amqp" + "git.pbiernat.dev/egommerce/basket-service/pkg/fluentd" + "github.com/jackc/pgx/v5/pgxpool" + base "github.com/streadway/amqp" +) + +type BasketService struct { + dbConn *pgxpool.Pool + ebCh *base.Channel + log *fluentd.Logger +} + +func NewBasketService(dbConn *pgxpool.Pool, chn *base.Channel, log *fluentd.Logger) *BasketService { + return &BasketService{dbConn, chn, log} +} + +func (s *BasketService) Get(basketID string) (interface{}, error) { + // basket := new(def.Basket) + var createdAt interface{} + row := s.dbConn.QueryRow(context.Background(), `SELECT created_at FROM "basket-svc".basket WHERE id=$1`, basketID) + err := row.Scan(createdAt) + if err != nil { + s.log.Log("GET CART: %v", err) + return nil, err + } + + return createdAt, nil +} + +func (s *BasketService) Create(basketID string) error { + sql := `INSERT INTO "basket-svc".basket(id) VALUES($1)` + _, err := s.dbConn.Exec(context.Background(), sql, basketID) + // s.dbConn.Query(context.Background(), `INSERT INTO "basket-svc".basket(id) VALUES($1)`, basketID) + + return err +} + +func (s *BasketService) Checkout(reqID, basketID string) (string, error) { + s.log.Log("Creating initial order from basket#:%s", basketID) + + msg := &event.BasketCheckoutEvent{Event: event.NewEvent(reqID), BasketID: basketID} + amqp.Publish(s.ebCh, "api-events", "basket.order.basketCheckout", msg) // fixme probably redundant in eventName in routingKey + + return basketID, nil +} diff --git a/src/pkg/amqp/connect.go b/src/pkg/amqp/connect.go new file mode 100644 index 0000000..9429823 --- /dev/null +++ b/src/pkg/amqp/connect.go @@ -0,0 +1,26 @@ +package amqp + +import ( + "log" + + "github.com/streadway/amqp" +) + +func Open(url string) (*amqp.Connection, *amqp.Channel, error) { + conn, err := amqp.Dial(url) + if err != nil { + return nil, nil, err + } + + ch, err := conn.Channel() + if err != nil { + log.Printf("Failed to open a channel: %v\n", err) + return nil, nil, err + } + + return conn, ch, nil +} + +func Close(conn *amqp.Connection) { + conn.Close() +} diff --git a/src/pkg/amqp/pubsub.go b/src/pkg/amqp/pubsub.go new file mode 100644 index 0000000..c4ff18d --- /dev/null +++ b/src/pkg/amqp/pubsub.go @@ -0,0 +1,86 @@ +package amqp + +import ( + "bytes" + "encoding/json" + "fmt" + + "github.com/streadway/amqp" +) + +const ( + EVENT_PRODUCT_ADDED_TO_BASKET = "event.ProductAddedToBasketEvent" + EVENT_PRODUCT_REMOVED_FROM_BASKET = "event.ProductRemovedFromBasketEvent" +) + +type Message map[string]interface{} + +func Serialize(msg any /*Message*/) ([]byte, error) { + var b bytes.Buffer + encoder := json.NewEncoder(&b) + err := encoder.Encode(msg) + return b.Bytes(), err +} + +func Deserialize(b []byte) (Message, error) { + var msg Message + buf := bytes.NewBuffer(b) + decoder := json.NewDecoder(buf) + err := decoder.Decode(&msg) + return msg, err +} + +func NewExchange(chn *amqp.Channel, name string) error { + err := chn.ExchangeDeclare( + name, + "direct", // type + true, // durable + false, // auto-deleted + false, // internal + false, // no-wait + nil, // arguments + ) // FIXME extend arguments when needed... + + if err != nil { + return err + } + + return nil +} + +func Publish(chn *amqp.Channel, name, routingKey string, msg any) error { + var jsonData []byte + jsonData, err := Serialize(msg) + if err != nil { + return err + } + + msgBody := fmt.Sprintf(`{"event":"%T","data":%s}`, msg, jsonData) // FIXME %T - simplify + chn.Publish( + name, // exchange name + routingKey, // routing key + false, // mandatory + false, // immediate + amqp.Publishing{ + ContentType: "application/json", + Body: []byte(msgBody), + }, + ) + + return nil +} + +func BindQueueToExchange(chn *amqp.Channel, queueName, exchName, routingKey string) error { + err := chn.QueueBind( + queueName, // queue name + routingKey, // routing key + exchName, // exchange name + false, + nil, + ) + if err != nil { + return err + } + + return nil +} diff --git a/src/pkg/consul/discovery.go b/src/pkg/consul/discovery.go new file mode 100644 index 0000000..3a73054 --- /dev/null +++ b/src/pkg/consul/discovery.go @@ -0,0 +1,107 @@ +package consul + +import ( + "log" + "strconv" + "time" + + consul "github.com/hashicorp/consul/api" +) + +type Service struct { + Name string + Address string + Port int + TTL time.Duration + ConsulAgent *consul.Agent +} + +func NewService(appName, appDomain string, port int) (*Service, error) { + s := new(Service) + s.Name = appName + s.Address = appDomain + s.Port = port + s.TTL = time.Second * 15 + + client, err := consul.NewClient(newClientConfig()) + if err != nil { + return nil, err + } + s.ConsulAgent = client.Agent() + + // tags := s.GetTags() + + return s, nil +} + +func newClientConfig() *consul.Config { + conf := consul.DefaultConfig() + conf.Address = "api-registry:8500" // FIXME:consul server + + return conf +} + +func (s *Service) Register() error { + serviceDef := &consul.AgentServiceRegistration{ + Name: s.Name, + Address: s.Address, + Port: s.Port, + Tags: s.getTags(), + Check: &consul.AgentServiceCheck{ + TTL: s.TTL.String(), + }, + } + + if err := s.ConsulAgent.ServiceRegister(serviceDef); err != nil { + return err + } + go s.UpdateTTL(serviceDef /*service.Check*/) + + return nil +} + +func (s *Service) UpdateTTL(service *consul.AgentServiceRegistration /*check func() (bool, error)*/) { + ticker := time.NewTicker(s.TTL / 2) + for range ticker.C { + s.update(service /*check*/) + } +} + +func (s *Service) update(service *consul.AgentServiceRegistration /*check func() (bool, error)*/) { + // ok, err := check() + // if !ok { + // log.Printf("err=\"Check failed\" msg=\"%s\"", err.Error()) + // if err := s.ConsulAgent.FailTTL("service:"+s.Name, err.Error()); err != nil { + // log.Println(err) + // } + // } else { + // log.Println("Updating service info...") + if err := s.ConsulAgent.PassTTL("service:"+service.Name, ""); err != nil { + log.Println(err) + } + // } +} + +func (s *Service) getTags() []string { + name, addr, port := s.Name, s.Address, strconv.Itoa(s.Port) + + tags := []string{ + "traefik.enable=true", + "traefik.http.routers." + name + ".rule=Host(`" + addr + "`)", + "traefik.http.routers." + name + ".entryPoints=https", + "traefik.http.routers." + name + ".service=" + name, + "traefik.http.routers." + name + ".middlewares=compress,requestid", + "traefik.http.routers." + name + ".tls=true", + "traefik.http.services." + name + ".loadbalancer.server.scheme=http", + "traefik.http.services." + name + ".loadbalancer.server.port=" + port, + "traefik.http.services." + name + ".loadbalancer.passhostheader=false", + "traefik.http.middlewares.compress.compress=true", + "traefik.http.middlewares.requestid.plugin.requestid.headerName=X-Request-ID", + // "traefik.http.services." + name + ".loadbalancer.healthcheck.path=/health", + // "traefik.http.services." + name + ".loadbalancer.healthcheck.interval=10s", + // "traefik.tls.certificates.certfile=/certs/client.cert", + // "traefik.tls.certificates.keyfile=/certs/client.key", + } + + return tags +} diff --git a/src/pkg/fluentd/config.go b/src/pkg/fluentd/config.go new file mode 100644 index 0000000..48255d2 --- /dev/null +++ b/src/pkg/fluentd/config.go @@ -0,0 +1,14 @@ +package fluentd + +import ( + "strconv" + "strings" +) + +func ParseAddr(addr string) (string, int) { + p := strings.Split(addr, ":") + fHost := p[0] + fPort, _ := strconv.Atoi(p[1]) + + return fHost, fPort +} diff --git a/src/pkg/fluentd/logger.go b/src/pkg/fluentd/logger.go new file mode 100644 index 0000000..b398595 --- /dev/null +++ b/src/pkg/fluentd/logger.go @@ -0,0 +1,41 @@ +package fluentd + +import ( + "fmt" + "log" + + "github.com/fluent/fluent-logger-golang/fluent" +) + +type Logger struct { + fluent *fluent.Fluent + appName string +} + +func NewLogger(appName, fHost string, fPort int) *Logger { + config := fluent.Config{ + FluentHost: fHost, + FluentPort: fPort, + // WriteTimeout: -1, + } + fluent, err := fluent.New(config) + if err != nil { + log.Panicf("Error connecting to api-logger: %v", err) + } + + return &Logger{fluent, appName} +} + +func (l *Logger) Log(format string, v ...any) { + mapData := map[string]string{ + "message": fmt.Sprintf(format, v...), + } + err := l.fluent.Post(l.appName, mapData) + if err != nil { + log.Println("Error sending log: ", err) + } +} + +func (l *Logger) Close() error { + return l.fluent.Close() +} From 8129280b0824f430011c1a001505c76cc06257dc Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Tue, 29 Nov 2022 23:35:00 +0100 Subject: [PATCH 02/17] CQ fix --- src/cmd/worker/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go index b23620e..5aed168 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -150,6 +150,6 @@ func main() { } // create basket if not exists, next update product quantity -func updateBasketState() { +// func updateBasketState() { -} +// } From 19e44b60f098200e1d1535b8fe0b97468c4941ae Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Wed, 30 Nov 2022 02:07:53 +0100 Subject: [PATCH 03/17] Refactored docker image builder script --- Dockerfile.builder | 14 +++++++++++++ Dockerfile.server | 30 --------------------------- Dockerfile.target | 22 ++++++++++++++++++++ Dockerfile.worker | 29 -------------------------- deploy/image-build.sh | 48 ++++++++++++++++++++++++------------------- 5 files changed, 63 insertions(+), 80 deletions(-) create mode 100644 Dockerfile.builder delete mode 100644 Dockerfile.server create mode 100644 Dockerfile.target delete mode 100644 Dockerfile.worker diff --git a/Dockerfile.builder b/Dockerfile.builder new file mode 100644 index 0000000..9a0110d --- /dev/null +++ b/Dockerfile.builder @@ -0,0 +1,14 @@ +# Builder +FROM golang:alpine + +ARG BIN_OUTPUT=/go/bin +ARG GO_SERVER=cmd/server/main.go +ARG GO_WORKER=cmd/worker/main.go + +WORKDIR /go/src/app +COPY src ./ + +RUN go mod download && \ + export CGO_ENABLED=0 ; export GOOS=linux ; export GOARCH=amd64 && \ + go build -ldflags="-w -s" -o "$BIN_OUTPUT/server" $GO_SERVER && \ + go build -ldflags="-w -s" -o "$BIN_OUTPUT/worker" $GO_WORKER diff --git a/Dockerfile.server b/Dockerfile.server deleted file mode 100644 index 00c5cb8..0000000 --- a/Dockerfile.server +++ /dev/null @@ -1,30 +0,0 @@ -# Builder -FROM golang:alpine AS builder - -ARG BIN_OUTPUT=/go/bin/server -ARG GO_MAIN=cmd/server/main.go - -WORKDIR /go/src/app -COPY src ./ - -RUN go mod download && \ - export CGO_ENABLED=0 ; export GOOS=linux ; export GOARCH=amd64 && \ - go build -ldflags="-w -s" -o $BIN_OUTPUT $GO_MAIN - - -# Destination image - server -FROM gcr.io/distroless/base-debian10 - -ARG BIN_OUTPUT=/go/bin/server - -LABEL author="Piotr Biernat" -LABEL service="basket-svc" -LABEL vendor="Egommerce" -LABEL version="1.0" - -WORKDIR / -COPY --from=builder $BIN_OUTPUT / -COPY .env.dist /.env - -EXPOSE 80 -ENTRYPOINT ["/server"] diff --git a/Dockerfile.target b/Dockerfile.target new file mode 100644 index 0000000..a5f3487 --- /dev/null +++ b/Dockerfile.target @@ -0,0 +1,22 @@ +# Builder +ARG BUILDER_IMAGE="git.pbiernat.dev/egommerce/basket-builder:latest" +FROM ${BUILDER_IMAGE} AS builder + +# Destination image - server +FROM gcr.io/distroless/base-debian10 + +ARG BIN_OUTPUT +ARG SVC_NAME +ARG SVC_VER + +LABEL author="Piotr Biernat" +LABEL vendor="egommerce" +LABEL service=${SVC_NAME} +LABEL version=${SVC_VER} + +WORKDIR / +COPY --from=builder $BIN_OUTPUT /app +COPY .env.dist /.env + +EXPOSE 80 +ENTRYPOINT ["/app"] diff --git a/Dockerfile.worker b/Dockerfile.worker deleted file mode 100644 index d2fc1e2..0000000 --- a/Dockerfile.worker +++ /dev/null @@ -1,29 +0,0 @@ -# Builder -FROM golang:alpine AS builder - -ARG BIN_OUTPUT=/go/bin/worker -ARG GO_WORKER=cmd/worker/main.go - -WORKDIR /go/src/app -COPY src ./ - -RUN go mod download && \ - export CGO_ENABLED=0 ; export GOOS=linux ; export GOARCH=amd64 && \ - go build -ldflags="-w -s" -o $BIN_OUTPUT $GO_WORKER - - -# Destination image - worker -FROM gcr.io/distroless/base-debian10 - -ARG BIN_OUTPUT=/go/bin/worker - -LABEL author="Piotr Biernat" -LABEL service="basket-worker" -LABEL vendor="Egommerce" -LABEL version="1.0" - -WORKDIR / -COPY --from=builder $BIN_OUTPUT / -COPY .env.dist /.env - -ENTRYPOINT ["/worker"] diff --git a/deploy/image-build.sh b/deploy/image-build.sh index e918399..7c1a09e 100755 --- a/deploy/image-build.sh +++ b/deploy/image-build.sh @@ -1,31 +1,37 @@ #!/bin/sh # RUN IN REPO ROOT DIR !! -export IMAGE_BASE="git.pbiernat.dev/egommerce/basket" -export SERVER_IMAGE="$IMAGE_BASE-svc" -export WORKER_IMAGE="$IMAGE_BASE-worker" +export IMAGE_PREFIX="git.pbiernat.dev/egommerce/basket" +export BUILDER_IMAGE="$IMAGE_PREFIX-builder:tmp" +export SERVER_IMAGE="$IMAGE_PREFIX-svc" +export WORKER_IMAGE="$IMAGE_PREFIX-worker" TARGET=${1:-latest} -KIND=${2:-all} -if [ $KIND = "svc" ] || [ $KIND = "all" ]; then - echo "Building: $SERVER_IMAGE:$TARGET" - if [ $TARGET = "dev" ] - then - docker build --rm --no-cache -t "$SERVER_IMAGE:$TARGET" -f Dockerfile.server . # >/dev/null 2>&1 - else - docker build --rm --cache-from "$SERVER_IMAGE:$TARGET" -t "$SERVER_IMAGE:$TARGET" -f Dockerfile.server . >/dev/null 2>&1 - fi -fi +docker build --no-cache -t "$BUILDER_IMAGE" -f Dockerfile.builder . >/dev/null && echo "Successfully tagged $BUILDER_IMAGE" -if [ $KIND = "worker" ] || [ $KIND = "all" ]; then - echo "Building: $WORKER_IMAGE:$TARGET" - if [ $TARGET = "dev" ] - then - docker build --rm --no-cache -t "$WORKER_IMAGE:$TARGET" -f Dockerfile.worker . # >/dev/null 2>&1 - else - docker build --rm --cache-from "$WORKER_IMAGE:$TARGET" -t "$WORKER_IMAGE:$TARGET" -f Dockerfile.worker . >/dev/null 2>&1 - fi +echo "Building target $IMAGE_PREFIX images..." +if [ $TARGET = "latest" ] +then + # SERVER + docker build --build-arg SVC_NAME=basket-svc --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/server \ + --rm --build-arg BUILDER_IMAGE --cache-from "$SERVER_IMAGE:$TARGET" \ + -t "$SERVER_IMAGE:$TARGET" -f Dockerfile.target . >/dev/null 2>&1 + + # WORKER + docker build --build-arg SVC_NAME=basket-worker --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/worker \ + --rm --build-arg BUILDER_IMAGE --cache-from "$WORKER_IMAGE:$TARGET" \ + -t "$WORKER_IMAGE:$TARGET" -f Dockerfile.target . >/dev/null 2>&1 +else + # SERVER + docker build --build-arg SVC_NAME=basket-svc --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/server \ + --rm --build-arg BUILDER_IMAGE --no-cache -t "$SERVER_IMAGE:$TARGET" -f Dockerfile.target . \ + >/dev/null && echo "Successfully tagged $SERVER_IMAGE:$TARGET" + + # WORKER + docker build --build-arg SVC_NAME=basket-worker --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/worker \ + --rm --build-arg BUILDER_IMAGE --no-cache -t "$WORKER_IMAGE:$TARGET" -f Dockerfile.target . \ + >/dev/null && echo "Successfully tagged $WORKER_IMAGE:$TARGET" fi echo "Done." From 2fcd542194e27188cd2fba4209697b53e1ade213 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Wed, 30 Nov 2022 02:11:23 +0100 Subject: [PATCH 04/17] CQ fix --- src/cmd/worker/main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go index 5aed168..07e9858 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -111,7 +111,7 @@ func main() { for d := range msgs { msg, err := amqp.Deserialize(d.Body) if err != nil { - logger.Log("json error:", err) + logger.Log("json error: %v", err) d.Reject(false) // FIXME: how to handle erros in queue...???? continue } @@ -128,10 +128,10 @@ func main() { // FIXME CHECK if basket exists _, err := basket.Get(basketID) if err != nil { - logger.Log("Basket#%s not found. Creating...", basketID) + logger.Log("Basket#:%s not found. Creating...", basketID) err := basket.Create(basketID) if err != nil { - logger.Log("Creating basket error: %s", err) + logger.Log("Creating basket error: %v", err) d.Reject(false) continue } From afc18d34e1a767eb63f6414e11b1b18e8fb96aed Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Thu, 1 Dec 2022 06:23:13 +0100 Subject: [PATCH 05/17] vendor support and image build optimalization --- Dockerfile.builder | 3 +- deploy/image-build.sh | 30 +++-- src/cmd/server/main.go | 4 +- src/cmd/worker/main.go | 23 +++- src/go.mod | 12 +- src/go.sum | 137 +++++++++++++++++++- src/internal/app/definition/basket_model.go | 14 +- src/internal/app/server/router.go | 2 +- src/internal/app/server/server.go | 4 +- src/internal/app/service/basket.go | 47 ++++--- src/pkg/amqp/connect.go | 26 ---- src/pkg/amqp/pubsub.go | 86 ------------ src/pkg/consul/discovery.go | 107 --------------- src/pkg/fluentd/config.go | 14 -- src/pkg/fluentd/logger.go | 41 ------ 15 files changed, 219 insertions(+), 331 deletions(-) delete mode 100644 src/pkg/amqp/connect.go delete mode 100644 src/pkg/amqp/pubsub.go delete mode 100644 src/pkg/consul/discovery.go delete mode 100644 src/pkg/fluentd/config.go delete mode 100644 src/pkg/fluentd/logger.go diff --git a/Dockerfile.builder b/Dockerfile.builder index 9a0110d..779d27f 100644 --- a/Dockerfile.builder +++ b/Dockerfile.builder @@ -8,7 +8,6 @@ ARG GO_WORKER=cmd/worker/main.go WORKDIR /go/src/app COPY src ./ -RUN go mod download && \ - export CGO_ENABLED=0 ; export GOOS=linux ; export GOARCH=amd64 && \ +RUN export CGO_ENABLED=0 ; export GOOS=linux ; export GOARCH=amd64 && \ go build -ldflags="-w -s" -o "$BIN_OUTPUT/server" $GO_SERVER && \ go build -ldflags="-w -s" -o "$BIN_OUTPUT/worker" $GO_WORKER diff --git a/deploy/image-build.sh b/deploy/image-build.sh index 7c1a09e..4f08733 100755 --- a/deploy/image-build.sh +++ b/deploy/image-build.sh @@ -8,30 +8,34 @@ export WORKER_IMAGE="$IMAGE_PREFIX-worker" TARGET=${1:-latest} -docker build --no-cache -t "$BUILDER_IMAGE" -f Dockerfile.builder . >/dev/null && echo "Successfully tagged $BUILDER_IMAGE" +[ ! -d \"src/vendor\" ] && sh -c "cd src; go mod vendor" + +export DOCKER_BUILDKIT=1 + +docker build -t "$BUILDER_IMAGE" -f Dockerfile.builder . >/dev/null 2>&1 && echo "Successfully tagged $BUILDER_IMAGE" echo "Building target $IMAGE_PREFIX images..." if [ $TARGET = "latest" ] then # SERVER - docker build --build-arg SVC_NAME=basket-svc --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/server \ - --rm --build-arg BUILDER_IMAGE --cache-from "$SERVER_IMAGE:$TARGET" \ - -t "$SERVER_IMAGE:$TARGET" -f Dockerfile.target . >/dev/null 2>&1 + docker build --build-arg SVC_NAME=catalog-svc --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/server \ + --rm --build-arg BUILDER_IMAGE --cache-from "$SERVER_IMAGE:$TARGET" -t "$SERVER_IMAGE:$TARGET" \ + -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" & # WORKER - docker build --build-arg SVC_NAME=basket-worker --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/worker \ - --rm --build-arg BUILDER_IMAGE --cache-from "$WORKER_IMAGE:$TARGET" \ - -t "$WORKER_IMAGE:$TARGET" -f Dockerfile.target . >/dev/null 2>&1 + docker build --build-arg SVC_NAME=catalog-worker --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/worker \ + --rm --build-arg BUILDER_IMAGE --cache-from "$WORKER_IMAGE:$TARGET" -t "$WORKER_IMAGE:$TARGET" \ + -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $WORKER_IMAGE:$TARGET" else # SERVER - docker build --build-arg SVC_NAME=basket-svc --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/server \ - --rm --build-arg BUILDER_IMAGE --no-cache -t "$SERVER_IMAGE:$TARGET" -f Dockerfile.target . \ - >/dev/null && echo "Successfully tagged $SERVER_IMAGE:$TARGET" + docker build --build-arg SVC_NAME=catalog-svc --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/server \ + --rm --build-arg BUILDER_IMAGE --no-cache -t "$SERVER_IMAGE:$TARGET" \ + -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" & # WORKER - docker build --build-arg SVC_NAME=basket-worker --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/worker \ - --rm --build-arg BUILDER_IMAGE --no-cache -t "$WORKER_IMAGE:$TARGET" -f Dockerfile.target . \ - >/dev/null && echo "Successfully tagged $WORKER_IMAGE:$TARGET" + docker build --build-arg SVC_NAME=catalog-worker --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/worker \ + --rm --build-arg BUILDER_IMAGE --no-cache -t "$WORKER_IMAGE:$TARGET" \ + -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $WORKER_IMAGE:$TARGET" fi echo "Done." diff --git a/src/cmd/server/main.go b/src/cmd/server/main.go index d17af5c..10c3e90 100644 --- a/src/cmd/server/main.go +++ b/src/cmd/server/main.go @@ -8,8 +8,8 @@ import ( "git.pbiernat.dev/egommerce/basket-service/internal/app/config" "git.pbiernat.dev/egommerce/basket-service/internal/app/database" "git.pbiernat.dev/egommerce/basket-service/internal/app/server" - "git.pbiernat.dev/egommerce/basket-service/pkg/amqp" - "git.pbiernat.dev/egommerce/basket-service/pkg/fluentd" + "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" + amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" ) const ( diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go index 07e9858..4e918f4 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -8,10 +8,11 @@ import ( "git.pbiernat.dev/egommerce/basket-service/internal/app/config" "git.pbiernat.dev/egommerce/basket-service/internal/app/database" + def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" "git.pbiernat.dev/egommerce/basket-service/internal/app/server" "git.pbiernat.dev/egommerce/basket-service/internal/app/service" - "git.pbiernat.dev/egommerce/basket-service/pkg/amqp" - "git.pbiernat.dev/egommerce/basket-service/pkg/fluentd" + "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" + amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" "github.com/google/uuid" ) @@ -106,7 +107,7 @@ func main() { var forever chan struct{} go func() { - basket := service.NewBasketService(dbConn, ebCh, logger) + bSrvc := service.NewBasketService(dbConn, ebCh, logger) for d := range msgs { msg, err := amqp.Deserialize(d.Body) @@ -120,16 +121,19 @@ func main() { data := (msg["data"]).(map[string]interface{}) logger.Log("Message<%s>: %#v", event, data) - basketID := data["basket_id"].(string) // FIXME CHECK basket_id!!! + basketID := data["basket_id"].(string) // FIXME Check input params! + productID := data["product_id"].(string) // FIXME Check input params! switch true { case strings.Contains(event, amqp.EVENT_PRODUCT_ADDED_TO_BASKET): // create new basket and add product to it // FIXME CHECK if basket exists - _, err := basket.Get(basketID) + + var basket *def.BasketModel + basket, err := bSrvc.FetchFromDB(basketID) if err != nil { logger.Log("Basket#:%s not found. Creating...", basketID) - err := basket.Create(basketID) + basket, err = bSrvc.Create(basketID) if err != nil { logger.Log("Creating basket error: %v", err) d.Reject(false) @@ -137,6 +141,13 @@ func main() { } } + err = bSrvc.AddProduct(productID, basketID, 1) // FIXME: change to Update quantity - which add or delete product to/from basket depends on new quantity + if err != nil { + logger.Log("Error adding product to basket: %v", err) + d.Reject(false) + } + logger.Log("Fetched basket: %v", basket) + case strings.Contains(event, amqp.EVENT_PRODUCT_REMOVED_FROM_BASKET): // remove product from basket } diff --git a/src/go.mod b/src/go.mod index 15331d1..f50d9f4 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,10 +3,13 @@ module git.pbiernat.dev/egommerce/basket-service go 1.18 require ( - github.com/fluent/fluent-logger-golang v1.9.0 + git.pbiernat.dev/egommerce/go-api-pkg/consul v0.0.0-20221201033742-97afd0d96662 + git.pbiernat.dev/egommerce/go-api-pkg/fluentd v0.0.0-20221201033742-97afd0d96662 + git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq v0.0.0-20221201033742-97afd0d96662 + github.com/georgysavva/scany/v2 v2.0.0 github.com/gofiber/fiber/v2 v2.40.1 github.com/google/uuid v1.3.0 - github.com/hashicorp/consul/api v1.17.0 + github.com/jackc/pgtype v1.12.0 github.com/jackc/pgx/v5 v5.1.1 github.com/joho/godotenv v1.4.0 github.com/streadway/amqp v1.0.0 @@ -15,14 +18,16 @@ require ( require ( github.com/andybalholm/brotli v1.0.4 // indirect github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect - github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/fatih/color v1.9.0 // indirect + github.com/fluent/fluent-logger-golang v1.9.0 // indirect + github.com/hashicorp/consul/api v1.18.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.1 // indirect github.com/hashicorp/go-hclog v0.12.0 // indirect github.com/hashicorp/go-immutable-radix v1.0.0 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/serf v0.10.1 // indirect + github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect github.com/jackc/puddle/v2 v2.1.2 // indirect @@ -34,7 +39,6 @@ require ( github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/philhofer/fwd v1.1.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/tinylib/msgp v1.1.6 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.41.0 // indirect diff --git a/src/go.sum b/src/go.sum index 28db6c8..493cea8 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,3 +1,11 @@ +git.pbiernat.dev/egommerce/go-api-pkg/consul v0.0.0-20221201033742-97afd0d96662 h1:Z6D9KDaHS/TL2jcY10M0UxqyGcaXn7jK7P6ja8+ytkg= +git.pbiernat.dev/egommerce/go-api-pkg/consul v0.0.0-20221201033742-97afd0d96662/go.mod h1:lDctRzmIVtFNCPrXAOAOQJvi52KjfOqhgTftQ6gTE7U= +git.pbiernat.dev/egommerce/go-api-pkg/fluentd v0.0.0-20221201033742-97afd0d96662 h1:AG5rRYaXQFyL9XtZLkKfBQGyOBbGRQAqrgtLL6KoQTo= +git.pbiernat.dev/egommerce/go-api-pkg/fluentd v0.0.0-20221201033742-97afd0d96662/go.mod h1:/7GWyTxCHuk7y1aQtxJkTMuXNG6utr8APWjvOp51H7A= +git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq v0.0.0-20221201033742-97afd0d96662 h1:2skXunz8yjmYK0H5VOsXRhuyFrPo86PpL4b8heBei3I= +git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq v0.0.0-20221201033742-97afd0d96662/go.mod h1:gJQ6go/IGbrDkIftZO8cubLCu8Rbt5SWCh4EZMcdsW8= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -7,7 +15,11 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -17,16 +29,24 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fluent/fluent-logger-golang v1.9.0 h1:zUdY44CHX2oIUc7VTNZc+4m+ORuO/mldQDA7czhWXEg= github.com/fluent/fluent-logger-golang v1.9.0/go.mod h1:2/HCT/jTy78yGyeNGQLGQsjF3zzzAuy6Xlk6FCMV5eU= +github.com/georgysavva/scany/v2 v2.0.0 h1:RGXqxDv4row7/FYoK8MRXAZXqoWF/NM+NP0q50k3DKU= +github.com/georgysavva/scany/v2 v2.0.0/go.mod h1:sigOdh+0qb/+aOs3TVhehVT10p8qJL7K/Zhyz8vWo38= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofiber/fiber/v2 v2.40.1 h1:pc7n9VVpGIqNsvg9IPLQhyFEMJL8gCs1kneH5D1pIl4= github.com/gofiber/fiber/v2 v2.40.1/go.mod h1:Gko04sLksnHbzLSRBFWPFdzM9Ws9pRxvvIaohJK1dsk= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/consul/api v1.17.0 h1:aqytbw31uCPNn37ST+717IyGod+P1eTgSGu3yjRo4bs= -github.com/hashicorp/consul/api v1.17.0/go.mod h1:ZNwemOPAdgtV4cCx9fqxNmw+PI3vliW6gYin2WD+F2g= +github.com/hashicorp/consul/api v1.18.0 h1:R7PPNzTCeN6VuQNDwwhZWJvzCtGSrNpJqfb22h3yH9g= +github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= github.com/hashicorp/consul/sdk v0.13.0 h1:lce3nFlpv8humJL8rNrrGHYSKc3q+Kxfeg3Ii1m6ZWU= github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -63,31 +83,84 @@ github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530 h1:dUJ578zuPEsXjtzOfEF0q9zDAfljJ9oFnTHcQaNkccw= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1 h1:7PQ/4gLoqnl87ZxL7xjO0DR5gYuviDCZxQJsUlFW1eI= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= +github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c h1:Dznn52SgVIVst9UyOT9brctYUgxs+CvVfPaC3jKrA50= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v5 v5.1.1 h1:pZD79K1SYv8wc2HmCQA6VdmRQi7/OtCfv9bM3WAXUYA= github.com/jackc/pgx/v5 v5.1.1/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle/v2 v2.1.2 h1:0f7vaaXINONKTsxYDn4otOAiJanX/BMeAtY//BXqzlg= github.com/jackc/puddle/v2 v2.1.2/go.mod h1:2lpufsF5mRHO6SuZkm0fNYxM6SWHfvyFj62KwNzgels= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= @@ -120,16 +193,26 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -145,18 +228,41 @@ github.com/valyala/fasthttp v1.41.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seB github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -171,9 +277,13 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc= golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -190,27 +300,42 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/src/internal/app/definition/basket_model.go b/src/internal/app/definition/basket_model.go index a477aca..232d622 100644 --- a/src/internal/app/definition/basket_model.go +++ b/src/internal/app/definition/basket_model.go @@ -1,9 +1,13 @@ package definition -import "time" +import ( + "time" -type Basket struct { - ID string `db:"id"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` + "github.com/jackc/pgtype" +) + +type BasketModel struct { + ID string `db:"id"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt pgtype.Timestamp `db:"updated_at"` } diff --git a/src/internal/app/server/router.go b/src/internal/app/server/router.go index 0409125..36be180 100644 --- a/src/internal/app/server/router.go +++ b/src/internal/app/server/router.go @@ -1,7 +1,7 @@ package server import ( - "git.pbiernat.dev/egommerce/basket-service/pkg/fluentd" + "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" "github.com/gofiber/fiber/v2" ) diff --git a/src/internal/app/server/server.go b/src/internal/app/server/server.go index 3e39ae7..9d988e1 100644 --- a/src/internal/app/server/server.go +++ b/src/internal/app/server/server.go @@ -9,8 +9,8 @@ import ( "github.com/jackc/pgx/v5/pgxpool" "github.com/streadway/amqp" - discovery "git.pbiernat.dev/egommerce/basket-service/pkg/consul" - "git.pbiernat.dev/egommerce/basket-service/pkg/fluentd" + discovery "git.pbiernat.dev/egommerce/go-api-pkg/consul" + "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" ) type Server struct { diff --git a/src/internal/app/service/basket.go b/src/internal/app/service/basket.go index 2973f67..af91b51 100644 --- a/src/internal/app/service/basket.go +++ b/src/internal/app/service/basket.go @@ -3,9 +3,10 @@ package service import ( "context" + def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" "git.pbiernat.dev/egommerce/basket-service/internal/app/event" - "git.pbiernat.dev/egommerce/basket-service/pkg/amqp" - "git.pbiernat.dev/egommerce/basket-service/pkg/fluentd" + "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" + "github.com/georgysavva/scany/v2/pgxscan" "github.com/jackc/pgx/v5/pgxpool" base "github.com/streadway/amqp" ) @@ -20,32 +21,46 @@ func NewBasketService(dbConn *pgxpool.Pool, chn *base.Channel, log *fluentd.Logg return &BasketService{dbConn, chn, log} } -func (s *BasketService) Get(basketID string) (interface{}, error) { - // basket := new(def.Basket) - var createdAt interface{} - row := s.dbConn.QueryRow(context.Background(), `SELECT created_at FROM "basket-svc".basket WHERE id=$1`, basketID) - err := row.Scan(createdAt) - if err != nil { - s.log.Log("GET CART: %v", err) +func (s *BasketService) Create(basketID string) (*def.BasketModel, error) { + ctx := context.Background() + + sql := `INSERT INTO "basket-svc".basket(id) VALUES($1)` + if _, err := s.dbConn.Exec(ctx, sql, basketID); err != nil { return nil, err } - return createdAt, nil + return &def.BasketModel{ID: basketID}, nil // FIXME - WTF is that xD?? } -func (s *BasketService) Create(basketID string) error { - sql := `INSERT INTO "basket-svc".basket(id) VALUES($1)` - _, err := s.dbConn.Exec(context.Background(), sql, basketID) - // s.dbConn.Query(context.Background(), `INSERT INTO "basket-svc".basket(id) VALUES($1)`, basketID) +func (s *BasketService) FetchFromDB(basketID string) (*def.BasketModel, error) { + ctx := context.Background() - return err + basket := new(def.BasketModel) + err := pgxscan.Get(ctx, s.dbConn, basket, `SELECT id, created_at, updated_at FROM "basket-svc".basket WHERE id=$1`, basketID) + if err != nil { + return nil, err + } + + return basket, nil +} + +func (s *BasketService) AddProduct(productId, basketID string, qty int) error { + ctx := context.Background() + s.log.Log("Adding product#:%s into Basket#:%s", productId, basketID) + + sql := `INSERT INTO "basket-svc".basket_item(basket_id, product_id) VALUES($1,$2)` + if _, err := s.dbConn.Exec(ctx, sql, basketID, productId); err != nil { + return err + } + + return nil } func (s *BasketService) Checkout(reqID, basketID string) (string, error) { s.log.Log("Creating initial order from basket#:%s", basketID) msg := &event.BasketCheckoutEvent{Event: event.NewEvent(reqID), BasketID: basketID} - amqp.Publish(s.ebCh, "api-events", "basket.order.basketCheckout", msg) // fixme probably redundant in eventName in routingKey + queue.Publish(s.ebCh, "api-events", "basket.order.basketCheckout", msg) // fixme probably redundant in eventName in routingKey return basketID, nil } diff --git a/src/pkg/amqp/connect.go b/src/pkg/amqp/connect.go deleted file mode 100644 index 9429823..0000000 --- a/src/pkg/amqp/connect.go +++ /dev/null @@ -1,26 +0,0 @@ -package amqp - -import ( - "log" - - "github.com/streadway/amqp" -) - -func Open(url string) (*amqp.Connection, *amqp.Channel, error) { - conn, err := amqp.Dial(url) - if err != nil { - return nil, nil, err - } - - ch, err := conn.Channel() - if err != nil { - log.Printf("Failed to open a channel: %v\n", err) - return nil, nil, err - } - - return conn, ch, nil -} - -func Close(conn *amqp.Connection) { - conn.Close() -} diff --git a/src/pkg/amqp/pubsub.go b/src/pkg/amqp/pubsub.go deleted file mode 100644 index c4ff18d..0000000 --- a/src/pkg/amqp/pubsub.go +++ /dev/null @@ -1,86 +0,0 @@ -package amqp - -import ( - "bytes" - "encoding/json" - "fmt" - - "github.com/streadway/amqp" -) - -const ( - EVENT_PRODUCT_ADDED_TO_BASKET = "event.ProductAddedToBasketEvent" - EVENT_PRODUCT_REMOVED_FROM_BASKET = "event.ProductRemovedFromBasketEvent" -) - -type Message map[string]interface{} - -func Serialize(msg any /*Message*/) ([]byte, error) { - var b bytes.Buffer - encoder := json.NewEncoder(&b) - err := encoder.Encode(msg) - return b.Bytes(), err -} - -func Deserialize(b []byte) (Message, error) { - var msg Message - buf := bytes.NewBuffer(b) - decoder := json.NewDecoder(buf) - err := decoder.Decode(&msg) - return msg, err -} - -func NewExchange(chn *amqp.Channel, name string) error { - err := chn.ExchangeDeclare( - name, - "direct", // type - true, // durable - false, // auto-deleted - false, // internal - false, // no-wait - nil, // arguments - ) // FIXME extend arguments when needed... - - if err != nil { - return err - } - - return nil -} - -func Publish(chn *amqp.Channel, name, routingKey string, msg any) error { - var jsonData []byte - jsonData, err := Serialize(msg) - if err != nil { - return err - } - - msgBody := fmt.Sprintf(`{"event":"%T","data":%s}`, msg, jsonData) // FIXME %T - simplify - chn.Publish( - name, // exchange name - routingKey, // routing key - false, // mandatory - false, // immediate - amqp.Publishing{ - ContentType: "application/json", - Body: []byte(msgBody), - }, - ) - - return nil -} - -func BindQueueToExchange(chn *amqp.Channel, queueName, exchName, routingKey string) error { - err := chn.QueueBind( - queueName, // queue name - routingKey, // routing key - exchName, // exchange name - false, - nil, - ) - if err != nil { - return err - } - - return nil -} diff --git a/src/pkg/consul/discovery.go b/src/pkg/consul/discovery.go deleted file mode 100644 index 3a73054..0000000 --- a/src/pkg/consul/discovery.go +++ /dev/null @@ -1,107 +0,0 @@ -package consul - -import ( - "log" - "strconv" - "time" - - consul "github.com/hashicorp/consul/api" -) - -type Service struct { - Name string - Address string - Port int - TTL time.Duration - ConsulAgent *consul.Agent -} - -func NewService(appName, appDomain string, port int) (*Service, error) { - s := new(Service) - s.Name = appName - s.Address = appDomain - s.Port = port - s.TTL = time.Second * 15 - - client, err := consul.NewClient(newClientConfig()) - if err != nil { - return nil, err - } - s.ConsulAgent = client.Agent() - - // tags := s.GetTags() - - return s, nil -} - -func newClientConfig() *consul.Config { - conf := consul.DefaultConfig() - conf.Address = "api-registry:8500" // FIXME:consul server - - return conf -} - -func (s *Service) Register() error { - serviceDef := &consul.AgentServiceRegistration{ - Name: s.Name, - Address: s.Address, - Port: s.Port, - Tags: s.getTags(), - Check: &consul.AgentServiceCheck{ - TTL: s.TTL.String(), - }, - } - - if err := s.ConsulAgent.ServiceRegister(serviceDef); err != nil { - return err - } - go s.UpdateTTL(serviceDef /*service.Check*/) - - return nil -} - -func (s *Service) UpdateTTL(service *consul.AgentServiceRegistration /*check func() (bool, error)*/) { - ticker := time.NewTicker(s.TTL / 2) - for range ticker.C { - s.update(service /*check*/) - } -} - -func (s *Service) update(service *consul.AgentServiceRegistration /*check func() (bool, error)*/) { - // ok, err := check() - // if !ok { - // log.Printf("err=\"Check failed\" msg=\"%s\"", err.Error()) - // if err := s.ConsulAgent.FailTTL("service:"+s.Name, err.Error()); err != nil { - // log.Println(err) - // } - // } else { - // log.Println("Updating service info...") - if err := s.ConsulAgent.PassTTL("service:"+service.Name, ""); err != nil { - log.Println(err) - } - // } -} - -func (s *Service) getTags() []string { - name, addr, port := s.Name, s.Address, strconv.Itoa(s.Port) - - tags := []string{ - "traefik.enable=true", - "traefik.http.routers." + name + ".rule=Host(`" + addr + "`)", - "traefik.http.routers." + name + ".entryPoints=https", - "traefik.http.routers." + name + ".service=" + name, - "traefik.http.routers." + name + ".middlewares=compress,requestid", - "traefik.http.routers." + name + ".tls=true", - "traefik.http.services." + name + ".loadbalancer.server.scheme=http", - "traefik.http.services." + name + ".loadbalancer.server.port=" + port, - "traefik.http.services." + name + ".loadbalancer.passhostheader=false", - "traefik.http.middlewares.compress.compress=true", - "traefik.http.middlewares.requestid.plugin.requestid.headerName=X-Request-ID", - // "traefik.http.services." + name + ".loadbalancer.healthcheck.path=/health", - // "traefik.http.services." + name + ".loadbalancer.healthcheck.interval=10s", - // "traefik.tls.certificates.certfile=/certs/client.cert", - // "traefik.tls.certificates.keyfile=/certs/client.key", - } - - return tags -} diff --git a/src/pkg/fluentd/config.go b/src/pkg/fluentd/config.go deleted file mode 100644 index 48255d2..0000000 --- a/src/pkg/fluentd/config.go +++ /dev/null @@ -1,14 +0,0 @@ -package fluentd - -import ( - "strconv" - "strings" -) - -func ParseAddr(addr string) (string, int) { - p := strings.Split(addr, ":") - fHost := p[0] - fPort, _ := strconv.Atoi(p[1]) - - return fHost, fPort -} diff --git a/src/pkg/fluentd/logger.go b/src/pkg/fluentd/logger.go deleted file mode 100644 index b398595..0000000 --- a/src/pkg/fluentd/logger.go +++ /dev/null @@ -1,41 +0,0 @@ -package fluentd - -import ( - "fmt" - "log" - - "github.com/fluent/fluent-logger-golang/fluent" -) - -type Logger struct { - fluent *fluent.Fluent - appName string -} - -func NewLogger(appName, fHost string, fPort int) *Logger { - config := fluent.Config{ - FluentHost: fHost, - FluentPort: fPort, - // WriteTimeout: -1, - } - fluent, err := fluent.New(config) - if err != nil { - log.Panicf("Error connecting to api-logger: %v", err) - } - - return &Logger{fluent, appName} -} - -func (l *Logger) Log(format string, v ...any) { - mapData := map[string]string{ - "message": fmt.Sprintf(format, v...), - } - err := l.fluent.Post(l.appName, mapData) - if err != nil { - log.Println("Error sending log: ", err) - } -} - -func (l *Logger) Close() error { - return l.fluent.Close() -} From 34d04efaf80253e85fcb73022d83c18d204b4dd8 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Fri, 2 Dec 2022 14:40:39 +0100 Subject: [PATCH 06/17] update --- Dockerfile.target | 3 +- deploy/image-build.sh | 8 +- src/cmd/server/main.go | 12 ++- src/cmd/worker/main.go | 30 ++++--- src/go.mod | 19 ++-- src/go.sum | 104 ++++++++++++++++++---- src/internal/app/log.go | 20 +++++ src/internal/app/server/basket_handler.go | 2 +- src/internal/app/server/config.go | 8 ++ src/internal/app/server/server.go | 53 ++++++----- src/internal/app/service/basket.go | 3 +- 11 files changed, 192 insertions(+), 70 deletions(-) create mode 100644 src/internal/app/log.go diff --git a/Dockerfile.target b/Dockerfile.target index a5f3487..52e351b 100644 --- a/Dockerfile.target +++ b/Dockerfile.target @@ -3,7 +3,8 @@ ARG BUILDER_IMAGE="git.pbiernat.dev/egommerce/basket-builder:latest" FROM ${BUILDER_IMAGE} AS builder # Destination image - server -FROM gcr.io/distroless/base-debian10 +# FROM gcr.io/distroless/base-debian10 +FROM alpine:3.17 ARG BIN_OUTPUT ARG SVC_NAME diff --git a/deploy/image-build.sh b/deploy/image-build.sh index 4f08733..90efe5c 100755 --- a/deploy/image-build.sh +++ b/deploy/image-build.sh @@ -18,22 +18,22 @@ echo "Building target $IMAGE_PREFIX images..." if [ $TARGET = "latest" ] then # SERVER - docker build --build-arg SVC_NAME=catalog-svc --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/server \ + docker build --build-arg SVC_NAME=basket-svc --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/server \ --rm --build-arg BUILDER_IMAGE --cache-from "$SERVER_IMAGE:$TARGET" -t "$SERVER_IMAGE:$TARGET" \ -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" & # WORKER - docker build --build-arg SVC_NAME=catalog-worker --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/worker \ + docker build --build-arg SVC_NAME=basket-worker --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/worker \ --rm --build-arg BUILDER_IMAGE --cache-from "$WORKER_IMAGE:$TARGET" -t "$WORKER_IMAGE:$TARGET" \ -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $WORKER_IMAGE:$TARGET" else # SERVER - docker build --build-arg SVC_NAME=catalog-svc --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/server \ + docker build --build-arg SVC_NAME=basket-svc --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/server \ --rm --build-arg BUILDER_IMAGE --no-cache -t "$SERVER_IMAGE:$TARGET" \ -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" & # WORKER - docker build --build-arg SVC_NAME=catalog-worker --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/worker \ + docker build --build-arg SVC_NAME=basket-worker --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/worker \ --rm --build-arg BUILDER_IMAGE --no-cache -t "$WORKER_IMAGE:$TARGET" \ -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $WORKER_IMAGE:$TARGET" fi diff --git a/src/cmd/server/main.go b/src/cmd/server/main.go index 10c3e90..16b0d4b 100644 --- a/src/cmd/server/main.go +++ b/src/cmd/server/main.go @@ -17,6 +17,7 @@ const ( defAppDomain = "basket-svc" defNetAddr = ":80" defLoggerAddr = "api-logger:24224" + defRegistryAddr = "api-registry:8500" defDbURL = "postgres://postgres:12345678@postgres-db:5432/egommerce" defMongoDbURL = "mongodb://mongodb:12345678@mongo-db:27017" defEventBusURL = "amqp://guest:guest@api-eventbus:5672" @@ -30,17 +31,19 @@ func main() { } c := new(server.Config) + c.AppID, _ = os.Hostname() c.AppName = config.GetEnv("APP_NAME", defAppName) c.AppDomain = config.GetEnv("APP_DOMAIN", defAppDomain) c.NetAddr = config.GetEnv("SERVER_ADDR", defNetAddr) c.Port, _ = strconv.Atoi(c.NetAddr[1:]) c.LoggerAddr = config.GetEnv("LOGGER_ADDR", defLoggerAddr) + c.RegistryAddr = config.GetEnv("REGISTRY_ADDR", defRegistryAddr) c.DbURL = config.GetEnv("DATABASE_URL", defDbURL) c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) c.EventBusExchange = ebEventsExchange logHost, logPort := fluentd.ParseAddr(c.LoggerAddr) - logger := fluentd.NewLogger(c.AppName, logHost, logPort) + logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) defer logger.Close() // db conn @@ -68,5 +71,10 @@ func main() { // start server srv := server.NewServer(c, logger, dbConn, ebCh) - srv.StartWithGracefulShutdown() + + forever := make(chan struct{}) + srv.StartWithGracefulShutdown(forever) + <-forever + + // os.Exit(1) } diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go index 4e918f4..828a5a7 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -4,7 +4,9 @@ import ( "fmt" "log" "os" + "os/signal" "strings" + "syscall" "git.pbiernat.dev/egommerce/basket-service/internal/app/config" "git.pbiernat.dev/egommerce/basket-service/internal/app/database" @@ -13,7 +15,6 @@ import ( "git.pbiernat.dev/egommerce/basket-service/internal/app/service" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" - "github.com/google/uuid" ) const ( @@ -31,18 +32,17 @@ func main() { log.Panicln("Error loading .env file", config.ErrLoadingEnvs) } - id := uuid.New().String()[24:] c := new(server.Config) - c.AppName = config.GetEnv("APP_NAME", defAppName) + "#:" + id + c.AppID, _ = os.Hostname() + c.AppName = config.GetEnv("APP_NAME", defAppName) c.LoggerAddr = config.GetEnv("LOGGER_ADDR", defLoggerAddr) c.DbURL = config.GetEnv("DATABASE_URL", defDbURL) c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) c.EventBusExchange = ebEventsExchange c.EventBusQueue = ebEventsQueue - // c.EventBusQueue = fmt.Sprintf("%s-%s", ebEventsQueue, id) logHost, logPort := fluentd.ParseAddr(c.LoggerAddr) - logger := fluentd.NewLogger(c.AppName, logHost, logPort) + logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) defer logger.Close() // db conn @@ -105,7 +105,17 @@ func main() { os.Exit(1) } - var forever chan struct{} + forever := make(chan struct{}) + go func() { + sigint := make(chan os.Signal, 1) + signal.Notify(sigint, os.Interrupt, os.Kill, syscall.SIGINT, syscall.SIGTERM) + <-sigint + + logger.Log("Worker %s stopped working...\n", c.GetAppFullName()) + + close(forever) + }() + go func() { bSrvc := service.NewBasketService(dbConn, ebCh, logger) @@ -119,7 +129,7 @@ func main() { event := fmt.Sprintf("%s", msg["event"]) data := (msg["data"]).(map[string]interface{}) - logger.Log("Message<%s>: %#v", event, data) + logger.Log("Message<%s>: %s\n", event, data) basketID := data["basket_id"].(string) // FIXME Check input params! productID := data["product_id"].(string) // FIXME Check input params! @@ -151,6 +161,7 @@ func main() { case strings.Contains(event, amqp.EVENT_PRODUCT_REMOVED_FROM_BASKET): // remove product from basket } + logger.Log("ACK: %s", event) d.Ack(false) } @@ -159,8 +170,3 @@ func main() { logger.Log("Waiting for messages...") <-forever } - -// create basket if not exists, next update product quantity -// func updateBasketState() { - -// } diff --git a/src/go.mod b/src/go.mod index f50d9f4..7a5b3c7 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,12 +3,9 @@ module git.pbiernat.dev/egommerce/basket-service go 1.18 require ( - git.pbiernat.dev/egommerce/go-api-pkg/consul v0.0.0-20221201033742-97afd0d96662 - git.pbiernat.dev/egommerce/go-api-pkg/fluentd v0.0.0-20221201033742-97afd0d96662 - git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq v0.0.0-20221201033742-97afd0d96662 + git.pbiernat.dev/egommerce/go-api-pkg v0.0.29 github.com/georgysavva/scany/v2 v2.0.0 github.com/gofiber/fiber/v2 v2.40.1 - github.com/google/uuid v1.3.0 github.com/jackc/pgtype v1.12.0 github.com/jackc/pgx/v5 v5.1.1 github.com/joho/godotenv v1.4.0 @@ -17,13 +14,13 @@ require ( require ( github.com/andybalholm/brotli v1.0.4 // indirect - github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect - github.com/fatih/color v1.9.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/fatih/color v1.13.0 // indirect github.com/fluent/fluent-logger-golang v1.9.0 // indirect github.com/hashicorp/consul/api v1.18.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.1 // indirect - github.com/hashicorp/go-hclog v0.12.0 // indirect - github.com/hashicorp/go-immutable-radix v1.0.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.3.1 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/serf v0.10.1 // indirect @@ -36,7 +33,7 @@ require ( github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/philhofer/fwd v1.1.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/tinylib/msgp v1.1.6 // indirect @@ -46,6 +43,6 @@ require ( go.uber.org/atomic v1.10.0 // indirect golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect + golang.org/x/sys v0.2.0 // indirect golang.org/x/text v0.3.8 // indirect ) diff --git a/src/go.sum b/src/go.sum index 493cea8..34bc20d 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,20 +1,28 @@ -git.pbiernat.dev/egommerce/go-api-pkg/consul v0.0.0-20221201033742-97afd0d96662 h1:Z6D9KDaHS/TL2jcY10M0UxqyGcaXn7jK7P6ja8+ytkg= -git.pbiernat.dev/egommerce/go-api-pkg/consul v0.0.0-20221201033742-97afd0d96662/go.mod h1:lDctRzmIVtFNCPrXAOAOQJvi52KjfOqhgTftQ6gTE7U= -git.pbiernat.dev/egommerce/go-api-pkg/fluentd v0.0.0-20221201033742-97afd0d96662 h1:AG5rRYaXQFyL9XtZLkKfBQGyOBbGRQAqrgtLL6KoQTo= -git.pbiernat.dev/egommerce/go-api-pkg/fluentd v0.0.0-20221201033742-97afd0d96662/go.mod h1:/7GWyTxCHuk7y1aQtxJkTMuXNG6utr8APWjvOp51H7A= -git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq v0.0.0-20221201033742-97afd0d96662 h1:2skXunz8yjmYK0H5VOsXRhuyFrPo86PpL4b8heBei3I= -git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq v0.0.0-20221201033742-97afd0d96662/go.mod h1:gJQ6go/IGbrDkIftZO8cubLCu8Rbt5SWCh4EZMcdsW8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.29 h1:EG6t3i0P8ENH3eRYPgjVE8UHpnif8UPYA/23e1Nm6n0= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.29/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -25,43 +33,58 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fluent/fluent-logger-golang v1.9.0 h1:zUdY44CHX2oIUc7VTNZc+4m+ORuO/mldQDA7czhWXEg= github.com/fluent/fluent-logger-golang v1.9.0/go.mod h1:2/HCT/jTy78yGyeNGQLGQsjF3zzzAuy6Xlk6FCMV5eU= github.com/georgysavva/scany/v2 v2.0.0 h1:RGXqxDv4row7/FYoK8MRXAZXqoWF/NM+NP0q50k3DKU= github.com/georgysavva/scany/v2 v2.0.0/go.mod h1:sigOdh+0qb/+aOs3TVhehVT10p8qJL7K/Zhyz8vWo38= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofiber/fiber/v2 v2.40.1 h1:pc7n9VVpGIqNsvg9IPLQhyFEMJL8gCs1kneH5D1pIl4= github.com/gofiber/fiber/v2 v2.40.1/go.mod h1:Gko04sLksnHbzLSRBFWPFdzM9Ws9pRxvvIaohJK1dsk= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/consul/api v1.18.0 h1:R7PPNzTCeN6VuQNDwwhZWJvzCtGSrNpJqfb22h3yH9g= github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= github.com/hashicorp/consul/sdk v0.13.0 h1:lce3nFlpv8humJL8rNrrGHYSKc3q+Kxfeg3Ii1m6ZWU= github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= +github.com/hashicorp/go-hclog v1.3.1 h1:vDwF1DFNZhntP4DAjuTpOw3uEgMUpXh1pB5fW9DqHpo= +github.com/hashicorp/go-hclog v1.3.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= @@ -133,15 +156,19 @@ github.com/jackc/puddle/v2 v2.1.2 h1:0f7vaaXINONKTsxYDn4otOAiJanX/BMeAtY//BXqzlg github.com/jackc/puddle/v2 v2.1.2/go.mod h1:2lpufsF5mRHO6SuZkm0fNYxM6SWHfvyFj62KwNzgels= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -156,6 +183,8 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -165,10 +194,12 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -178,12 +209,20 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ= github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -191,6 +230,17 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -205,6 +255,7 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= @@ -218,9 +269,11 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/tinylib/msgp v1.1.6 h1:i+SbKraHhnrf9M5MYmvQhFnbLhAXSDWF8WWsuyRdocw= github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.41.0 h1:zeR0Z1my1wDHTRiamBCXVglQdbUwgb9uWG3k1HQz6jY= @@ -242,6 +295,7 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -259,8 +313,10 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -271,13 +327,17 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo= golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc= golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -289,6 +349,7 @@ golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -296,10 +357,14 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -329,13 +394,18 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/src/internal/app/log.go b/src/internal/app/log.go new file mode 100644 index 0000000..1728b1a --- /dev/null +++ b/src/internal/app/log.go @@ -0,0 +1,20 @@ +package app + +import ( + "log" +) + +const AppName = "basket-svc" + +func Panic(v ...any) { + log.Panicln(AppName+":", v) +} + +func Panicf(format string, v ...any) { + log.Panicf(AppName+": "+format, v...) +} + +func Panicln(v ...any) { + v = append([]any{AppName + ":"}, v...) + log.Panicln(v...) +} diff --git a/src/internal/app/server/basket_handler.go b/src/internal/app/server/basket_handler.go index 078bb7a..24c71e7 100644 --- a/src/internal/app/server/basket_handler.go +++ b/src/internal/app/server/basket_handler.go @@ -15,7 +15,7 @@ func (s *Server) CheckoutHandler(c *fiber.Ctx) error { basketID := data.BasketID // vlaidate, pre check... etc - basket := service.NewBasketService(s.dbConn, s.ebCh, s.log) + basket := service.NewBasketService(s.db, s.ebCh, s.log) basket.Checkout(reqID, basketID) return c.JSON(&def.BasketCheckoutResponse{ diff --git a/src/internal/app/server/config.go b/src/internal/app/server/config.go index 9d81e64..9bec52b 100644 --- a/src/internal/app/server/config.go +++ b/src/internal/app/server/config.go @@ -1,14 +1,22 @@ package server +import "fmt" + type Config struct { + AppID string AppName string AppDomain string NetAddr string Port int LoggerAddr string + RegistryAddr string DbURL string MongoDbUrl string EventBusURL string EventBusExchange string EventBusQueue string } + +func (c *Config) GetAppFullName() string { + return fmt.Sprintf("%s_%s", c.AppName, c.AppID) +} diff --git a/src/internal/app/server/server.go b/src/internal/app/server/server.go index 9d988e1..bdc1188 100644 --- a/src/internal/app/server/server.go +++ b/src/internal/app/server/server.go @@ -3,6 +3,7 @@ package server import ( "os" "os/signal" + "syscall" "time" "github.com/gofiber/fiber/v2" @@ -15,32 +16,34 @@ import ( type Server struct { *fiber.App - log *fluentd.Logger - dbConn *pgxpool.Pool - ebCh *amqp.Channel - name string - addr string + log *fluentd.Logger + db *pgxpool.Pool + ebCh *amqp.Channel + discovery *discovery.Service + name string + addr string } -type RequestID struct { +type Headers struct { RequestID string `reqHeader:"x-request-id"` } func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amqp.Channel) *Server { - discovery, err := discovery.NewService(conf.AppName, conf.AppDomain, conf.Port) + logger.Log("API_ID: %s", conf.AppID) + discovery, err := discovery.NewService(conf.RegistryAddr, conf.AppID, conf.AppName, conf.AppID, conf.AppDomain, conf.Port) if err != nil { - logger.Log("Error connecting to api-registry: %v", err) + logger.Log("Error connecting to %s: %v", conf.RegistryAddr, err) } logger.Log("Registering service with name: %s, address: %s", discovery.Name, discovery.Address) err = discovery.Register() if err != nil { - logger.Log(err.Error()) + logger.Log("register error: %v", err) } cnf := fiber.Config{ AppName: conf.AppName, - ServerHeader: conf.AppDomain, + ServerHeader: conf.AppName, ReadTimeout: time.Millisecond * 50, WriteTimeout: time.Millisecond * 50, IdleTimeout: time.Millisecond * 50, @@ -50,6 +53,7 @@ func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amq logger, db, ebCh, + discovery, conf.AppName, conf.NetAddr, } @@ -65,33 +69,28 @@ func (s *Server) Start() { s.log.Log("Starting error: %v", err) } -func (s *Server) StartWithGracefulShutdown() { - idle := make(chan struct{}) - +func (s *Server) StartWithGracefulShutdown(forever chan struct{}) { go func() { sigint := make(chan os.Signal, 1) - signal.Notify(sigint, os.Interrupt) + signal.Notify(sigint, os.Interrupt, os.Kill, syscall.SIGINT, syscall.SIGTERM) <-sigint - if err := s.Shutdown(); err != nil { + if err := s.gracefulShutdown(); err != nil { s.log.Log("Server is not shutting down! Reason: %v", err) } - s.log.Log("Servier is going down...") - // remove info from registry and close all connection here... - - close(idle) + close(forever) }() if err := s.Listen(s.addr); err != nil { s.log.Log("Server is not running! Reason: %v", err) } - <-idle + <-forever } func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) { - var hdr = new(RequestID) + var hdr = new(Headers) if err := c.ReqHeaderParser(hdr); err != nil { return "", err } @@ -99,3 +98,15 @@ func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) { return hdr.RequestID, nil } + +func (s *Server) gracefulShutdown() error { + s.log.Log("Server is going down...") + s.log.Log("Unregistering service: %s", s.discovery.GetID()) + s.discovery.Unregister() + + s.ebCh.Close() + s.db.Close() + s.log.Close() + + return s.Shutdown() +} diff --git a/src/internal/app/service/basket.go b/src/internal/app/service/basket.go index af91b51..9eb9fa6 100644 --- a/src/internal/app/service/basket.go +++ b/src/internal/app/service/basket.go @@ -6,6 +6,7 @@ import ( def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" "git.pbiernat.dev/egommerce/basket-service/internal/app/event" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" + amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" "github.com/georgysavva/scany/v2/pgxscan" "github.com/jackc/pgx/v5/pgxpool" base "github.com/streadway/amqp" @@ -60,7 +61,7 @@ func (s *BasketService) Checkout(reqID, basketID string) (string, error) { s.log.Log("Creating initial order from basket#:%s", basketID) msg := &event.BasketCheckoutEvent{Event: event.NewEvent(reqID), BasketID: basketID} - queue.Publish(s.ebCh, "api-events", "basket.order.basketCheckout", msg) // fixme probably redundant in eventName in routingKey + amqp.Publish(s.ebCh, "api-events", "basket.order.basketCheckout", msg) // fixme probably redundant in eventName in routingKey return basketID, nil } From 5efc8296e54dcc5d3c6233ed97f9418ea0e14484 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Fri, 2 Dec 2022 20:12:02 +0100 Subject: [PATCH 07/17] Refactor. Consul TTl fix, gracefull shutdown --- Dockerfile.target | 8 ++++---- deploy/image-build.sh | 2 +- src/cmd/worker/main.go | 20 ++++++++++---------- src/go.mod | 2 +- src/go.sum | 12 ++++++++++-- src/internal/app/event/basket.go | 5 +++++ src/internal/app/event/order.go | 4 ++++ src/internal/app/server/server.go | 3 +-- src/internal/app/service/basket.go | 2 +- 9 files changed, 37 insertions(+), 21 deletions(-) diff --git a/Dockerfile.target b/Dockerfile.target index 52e351b..f5a8ad5 100644 --- a/Dockerfile.target +++ b/Dockerfile.target @@ -10,10 +10,10 @@ ARG BIN_OUTPUT ARG SVC_NAME ARG SVC_VER -LABEL author="Piotr Biernat" -LABEL vendor="egommerce" -LABEL service=${SVC_NAME} -LABEL version=${SVC_VER} +LABEL dev.egommerce.image.author="Piotr Biernat" +LABEL dev.egommerce.image.service="api-eventubus" +LABEL dev.egommerce.image.service=${SVC_NAME} +LABEL dev.egommerce.image.version=${SVC_VER} WORKDIR / COPY --from=builder $BIN_OUTPUT /app diff --git a/deploy/image-build.sh b/deploy/image-build.sh index 90efe5c..2d64c2f 100755 --- a/deploy/image-build.sh +++ b/deploy/image-build.sh @@ -12,7 +12,7 @@ TARGET=${1:-latest} export DOCKER_BUILDKIT=1 -docker build -t "$BUILDER_IMAGE" -f Dockerfile.builder . >/dev/null 2>&1 && echo "Successfully tagged $BUILDER_IMAGE" +docker build -t "$BUILDER_IMAGE" -f Dockerfile.builder . && echo "Successfully tagged $BUILDER_IMAGE" || echo "Build failed. Exit." echo "Building target $IMAGE_PREFIX images..." if [ $TARGET = "latest" ] diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go index 828a5a7..efa5230 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -11,6 +11,7 @@ import ( "git.pbiernat.dev/egommerce/basket-service/internal/app/config" "git.pbiernat.dev/egommerce/basket-service/internal/app/database" def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" + "git.pbiernat.dev/egommerce/basket-service/internal/app/event" "git.pbiernat.dev/egommerce/basket-service/internal/app/server" "git.pbiernat.dev/egommerce/basket-service/internal/app/service" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" @@ -91,6 +92,7 @@ func main() { // os.Exit(1) // } + // event consume msgs, err := ebCh.Consume( c.EventBusQueue, // queue "", // consumer @@ -108,7 +110,7 @@ func main() { forever := make(chan struct{}) go func() { sigint := make(chan os.Signal, 1) - signal.Notify(sigint, os.Interrupt, os.Kill, syscall.SIGINT, syscall.SIGTERM) + signal.Notify(sigint, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) <-sigint logger.Log("Worker %s stopped working...\n", c.GetAppFullName()) @@ -122,23 +124,20 @@ func main() { for d := range msgs { msg, err := amqp.Deserialize(d.Body) if err != nil { - logger.Log("json error: %v", err) + logger.Log("json error: %v\n", err) d.Reject(false) // FIXME: how to handle erros in queue...???? continue } - event := fmt.Sprintf("%s", msg["event"]) + eName := fmt.Sprintf("%s", msg["event"]) data := (msg["data"]).(map[string]interface{}) - logger.Log("Message<%s>: %s\n", event, data) + logger.Log("Message<%s>: %s\n", eName, data) basketID := data["basket_id"].(string) // FIXME Check input params! productID := data["product_id"].(string) // FIXME Check input params! switch true { - case strings.Contains(event, amqp.EVENT_PRODUCT_ADDED_TO_BASKET): - // create new basket and add product to it - // FIXME CHECK if basket exists - + case strings.Contains(eName, event.EVENT_PRODUCT_ADDED_TO_BASKET): var basket *def.BasketModel basket, err := bSrvc.FetchFromDB(basketID) if err != nil { @@ -158,11 +157,12 @@ func main() { } logger.Log("Fetched basket: %v", basket) - case strings.Contains(event, amqp.EVENT_PRODUCT_REMOVED_FROM_BASKET): + case strings.Contains(eName, event.EVENT_PRODUCT_REMOVED_FROM_BASKET): // remove product from basket + logger.Log("Event: %s", event.EVENT_PRODUCT_REMOVED_FROM_BASKET) } - logger.Log("ACK: %s", event) + logger.Log("ACK: %s", eName) d.Ack(false) } }() diff --git a/src/go.mod b/src/go.mod index 7a5b3c7..93462be 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,7 +3,7 @@ module git.pbiernat.dev/egommerce/basket-service go 1.18 require ( - git.pbiernat.dev/egommerce/go-api-pkg v0.0.29 + git.pbiernat.dev/egommerce/go-api-pkg v0.0.101 github.com/georgysavva/scany/v2 v2.0.0 github.com/gofiber/fiber/v2 v2.40.1 github.com/jackc/pgtype v1.12.0 diff --git a/src/go.sum b/src/go.sum index 34bc20d..d9d9f5f 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,5 +1,13 @@ -git.pbiernat.dev/egommerce/go-api-pkg v0.0.29 h1:EG6t3i0P8ENH3eRYPgjVE8UHpnif8UPYA/23e1Nm6n0= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.29/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.32 h1:ArB/n30m927WMAM4u51guH+qR0Lu4NGyYnYdi7OhlzY= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.32/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.33 h1:1tm+pvUeS6OZLvHmLM3BwFS0Ty/eA3jDRuB60OicosA= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.33/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.34 h1:UO1x6O+cyU7yYYbDCDyhhAypuf4QGIXcmWcBEEjLuYM= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.34/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.100 h1:jw4fiGbZTsfJXJpGV+HQiYeMGZ7DMRMoepjuIwY6FIU= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.100/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.101 h1:NZCFAAlC94+LcN1gjrENnWUHvpWgaNksyB2N4Fiy8C4= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.101/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= diff --git a/src/internal/app/event/basket.go b/src/internal/app/event/basket.go index 0e8f578..93f91df 100644 --- a/src/internal/app/event/basket.go +++ b/src/internal/app/event/basket.go @@ -1,5 +1,10 @@ package event +const ( + EVENT_PRODUCT_ADDED_TO_BASKET = "event.ProductAddedToBasketEvent" + EVENT_PRODUCT_REMOVED_FROM_BASKET = "event.ProductRemovedFromBasketEvent" +) + type ProductAddedToBasketEvent struct { *Event ProductID string `json:"product_id"` diff --git a/src/internal/app/event/order.go b/src/internal/app/event/order.go index e5cad99..8eeb082 100644 --- a/src/internal/app/event/order.go +++ b/src/internal/app/event/order.go @@ -1,5 +1,9 @@ package event +const ( + EVENT_BASKET_CHECKOUT = "event.BasketCheckoutEvent" +) + type BasketCheckoutEvent struct { *Event BasketID string `json:"basket_id"` diff --git a/src/internal/app/server/server.go b/src/internal/app/server/server.go index bdc1188..331cc2a 100644 --- a/src/internal/app/server/server.go +++ b/src/internal/app/server/server.go @@ -72,7 +72,7 @@ func (s *Server) Start() { func (s *Server) StartWithGracefulShutdown(forever chan struct{}) { go func() { sigint := make(chan os.Signal, 1) - signal.Notify(sigint, os.Interrupt, os.Kill, syscall.SIGINT, syscall.SIGTERM) + signal.Notify(sigint, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) <-sigint if err := s.gracefulShutdown(); err != nil { @@ -96,7 +96,6 @@ func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) { } return hdr.RequestID, nil - } func (s *Server) gracefulShutdown() error { diff --git a/src/internal/app/service/basket.go b/src/internal/app/service/basket.go index 9eb9fa6..233da06 100644 --- a/src/internal/app/service/basket.go +++ b/src/internal/app/service/basket.go @@ -61,7 +61,7 @@ func (s *BasketService) Checkout(reqID, basketID string) (string, error) { s.log.Log("Creating initial order from basket#:%s", basketID) msg := &event.BasketCheckoutEvent{Event: event.NewEvent(reqID), BasketID: basketID} - amqp.Publish(s.ebCh, "api-events", "basket.order.basketCheckout", msg) // fixme probably redundant in eventName in routingKey + amqp.Publish(s.ebCh, "api-events", "basket.order.basketCheckout", msg) return basketID, nil } From 463b99433ada00169fdf647e4281544c9afa3e19 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Fri, 2 Dec 2022 21:54:45 +0100 Subject: [PATCH 08/17] Skip logging of health check requests --- Dockerfile.target | 2 +- src/internal/app/server/router.go | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Dockerfile.target b/Dockerfile.target index f5a8ad5..04f08d8 100644 --- a/Dockerfile.target +++ b/Dockerfile.target @@ -11,7 +11,7 @@ ARG SVC_NAME ARG SVC_VER LABEL dev.egommerce.image.author="Piotr Biernat" -LABEL dev.egommerce.image.service="api-eventubus" +LABEL dev.egommerce.image.vendor="Egommerce" LABEL dev.egommerce.image.service=${SVC_NAME} LABEL dev.egommerce.image.version=${SVC_VER} diff --git a/src/internal/app/server/router.go b/src/internal/app/server/router.go index 36be180..29e97ac 100644 --- a/src/internal/app/server/router.go +++ b/src/internal/app/server/router.go @@ -1,6 +1,8 @@ package server import ( + "strings" + "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" "github.com/gofiber/fiber/v2" ) @@ -20,6 +22,11 @@ func SetupMiddlewares(s *Server) { // Middlewares func LoggingMiddleware(log *fluentd.Logger) func(c *fiber.Ctx) error { return func(c *fiber.Ctx) error { + path := string(c.Request().URI().Path()) + if strings.Contains(path, "/health") { + return c.Next() + } + log.Log("Request: %s, remote: %s, via: %s", c.Request().URI().String(), c.Context().RemoteIP().String(), From bf875dccdd2379349838d59159498154951f6e05 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Fri, 2 Dec 2022 23:36:23 +0100 Subject: [PATCH 09/17] build fix --- deploy/image-push.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/deploy/image-push.sh b/deploy/image-push.sh index dd8e644..491e8ad 100755 --- a/deploy/image-push.sh +++ b/deploy/image-push.sh @@ -5,6 +5,8 @@ export IMAGE_BASE="git.pbiernat.dev/egommerce/basket" export SERVER_IMAGE="$IMAGE_BASE-svc" export WORKER_IMAGE="$IMAGE_BASE-worker" +TARGET=${1:-latest} + echo $DOCKER_PASSWORD | docker login git.pbiernat.dev -u $DOCKER_USERNAME --password-stdin -docker push "$SERVER_IMAGE:latest" -docker push "$WORKER_IMAGE:latest" +docker push "$SERVER_IMAGE:$TARGET" +docker push "$WORKER_IMAGE:$TARGET" From cfa1dfe9849281f8b5b095c0bc636f441c6cac90 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Tue, 6 Dec 2022 00:02:05 +0100 Subject: [PATCH 10/17] Added KV Config support and updated build scripts --- Dockerfile.target | 4 ++- deploy/image-build.sh | 24 ++++++------- deploy/image-push.sh | 1 + src/cmd/server/main.go | 2 ++ src/cmd/worker/main.go | 44 +++++++++++++++++++++++ src/go.mod | 2 +- src/go.sum | 20 +++++------ src/internal/app/server/config.go | 30 +++++++++------- src/internal/app/server/health_handler.go | 4 +++ src/internal/app/server/router.go | 5 +-- src/internal/app/server/server.go | 43 +++++++++++++++++++--- 11 files changed, 137 insertions(+), 42 deletions(-) diff --git a/Dockerfile.target b/Dockerfile.target index 04f08d8..dd6760b 100644 --- a/Dockerfile.target +++ b/Dockerfile.target @@ -1,11 +1,12 @@ # Builder -ARG BUILDER_IMAGE="git.pbiernat.dev/egommerce/basket-builder:latest" +ARG BUILDER_IMAGE FROM ${BUILDER_IMAGE} AS builder # Destination image - server # FROM gcr.io/distroless/base-debian10 FROM alpine:3.17 +ARG BUILD_TIME ARG BIN_OUTPUT ARG SVC_NAME ARG SVC_VER @@ -14,6 +15,7 @@ LABEL dev.egommerce.image.author="Piotr Biernat" LABEL dev.egommerce.image.vendor="Egommerce" LABEL dev.egommerce.image.service=${SVC_NAME} LABEL dev.egommerce.image.version=${SVC_VER} +LABEL dev.egommerce.image.build_time=${BUILD_TIME} WORKDIR / COPY --from=builder $BIN_OUTPUT /app diff --git a/deploy/image-build.sh b/deploy/image-build.sh index 2d64c2f..c5e7b34 100755 --- a/deploy/image-build.sh +++ b/deploy/image-build.sh @@ -2,39 +2,39 @@ # RUN IN REPO ROOT DIR !! export IMAGE_PREFIX="git.pbiernat.dev/egommerce/basket" -export BUILDER_IMAGE="$IMAGE_PREFIX-builder:tmp" +export BUILDER_IMAGE="egommerce-builder:basket" +export BUILD_TIME=$(date +"%Y%m%d%H%M%S") export SERVER_IMAGE="$IMAGE_PREFIX-svc" export WORKER_IMAGE="$IMAGE_PREFIX-worker" +export DOCKER_BUILDKIT=1 TARGET=${1:-latest} -[ ! -d \"src/vendor\" ] && sh -c "cd src; go mod vendor" - -export DOCKER_BUILDKIT=1 - -docker build -t "$BUILDER_IMAGE" -f Dockerfile.builder . && echo "Successfully tagged $BUILDER_IMAGE" || echo "Build failed. Exit." +[ ! -d "src/vendor" ] && sh -c "cd src; go mod vendor" echo "Building target $IMAGE_PREFIX images..." +docker build --rm -t "$BUILDER_IMAGE" -f Dockerfile.builder . + if [ $TARGET = "latest" ] then # SERVER docker build --build-arg SVC_NAME=basket-svc --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/server \ - --rm --build-arg BUILDER_IMAGE --cache-from "$SERVER_IMAGE:$TARGET" -t "$SERVER_IMAGE:$TARGET" \ - -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" & + --build-arg BUILDER_IMAGE=$BUILDER_IMAGE --build-arg BUILD_TIME --rm --cache-from "$SERVER_IMAGE:$TARGET" -t "$SERVER_IMAGE:$TARGET" \ + -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" # WORKER docker build --build-arg SVC_NAME=basket-worker --build-arg SVC_VER="1.0" --build-arg BIN_OUTPUT=/go/bin/worker \ - --rm --build-arg BUILDER_IMAGE --cache-from "$WORKER_IMAGE:$TARGET" -t "$WORKER_IMAGE:$TARGET" \ + --build-arg BUILDER_IMAGE=$BUILDER_IMAGE --build-arg BUILD_TIME --rm --cache-from "$WORKER_IMAGE:$TARGET" -t "$WORKER_IMAGE:$TARGET" \ -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $WORKER_IMAGE:$TARGET" else # SERVER docker build --build-arg SVC_NAME=basket-svc --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/server \ - --rm --build-arg BUILDER_IMAGE --no-cache -t "$SERVER_IMAGE:$TARGET" \ - -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" & + --build-arg BUILDER_IMAGE=$BUILDER_IMAGE --build-arg BUILD_TIME --rm --no-cache -t "$SERVER_IMAGE:$TARGET" \ + -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" # WORKER docker build --build-arg SVC_NAME=basket-worker --build-arg SVC_VER="dev" --build-arg BIN_OUTPUT=/go/bin/worker \ - --rm --build-arg BUILDER_IMAGE --no-cache -t "$WORKER_IMAGE:$TARGET" \ + --build-arg BUILDER_IMAGE=$BUILDER_IMAGE --build-arg BUILD_TIME --rm --no-cache -t "$WORKER_IMAGE:$TARGET" \ -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $WORKER_IMAGE:$TARGET" fi diff --git a/deploy/image-push.sh b/deploy/image-push.sh index 491e8ad..3060331 100755 --- a/deploy/image-push.sh +++ b/deploy/image-push.sh @@ -8,5 +8,6 @@ export WORKER_IMAGE="$IMAGE_BASE-worker" TARGET=${1:-latest} echo $DOCKER_PASSWORD | docker login git.pbiernat.dev -u $DOCKER_USERNAME --password-stdin + docker push "$SERVER_IMAGE:$TARGET" docker push "$WORKER_IMAGE:$TARGET" diff --git a/src/cmd/server/main.go b/src/cmd/server/main.go index 16b0d4b..163eb3e 100644 --- a/src/cmd/server/main.go +++ b/src/cmd/server/main.go @@ -23,6 +23,7 @@ const ( defEventBusURL = "amqp://guest:guest@api-eventbus:5672" ebEventsExchange = "api-events" ebEventsQueue = "basket-svc" + defKVNmspc = "dev.egommerce/service/basket-svc" ) func main() { @@ -41,6 +42,7 @@ func main() { c.DbURL = config.GetEnv("DATABASE_URL", defDbURL) c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) c.EventBusExchange = ebEventsExchange + c.KVNamespace = config.GetEnv("APP_KV_NAMESPACE", defKVNmspc) logHost, logPort := fluentd.ParseAddr(c.LoggerAddr) logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go index efa5230..b3e3727 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -1,12 +1,16 @@ package main import ( + "bytes" + "encoding/json" + "errors" "fmt" "log" "os" "os/signal" "strings" "syscall" + "time" "git.pbiernat.dev/egommerce/basket-service/internal/app/config" "git.pbiernat.dev/egommerce/basket-service/internal/app/database" @@ -14,6 +18,7 @@ import ( "git.pbiernat.dev/egommerce/basket-service/internal/app/event" "git.pbiernat.dev/egommerce/basket-service/internal/app/server" "git.pbiernat.dev/egommerce/basket-service/internal/app/service" + discovery "git.pbiernat.dev/egommerce/go-api-pkg/consul" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" ) @@ -21,11 +26,13 @@ import ( const ( defAppName = "basket-worker" defLoggerAddr = "api-logger:24224" + defRegistryAddr = "api-registry:8500" defDbURL = "postgres://postgres:12345678@postgres-db:5432/egommerce" defMongoDbURL = "mongodb://mongodb:12345678@mongo-db:27017" defEventBusURL = "amqp://guest:guest@api-eventbus:5672" ebEventsExchange = "api-events" ebEventsQueue = "basket-worker" + defKVNmspc = "dev.egommerce/service/basket-worker" ) func main() { @@ -37,15 +44,33 @@ func main() { c.AppID, _ = os.Hostname() c.AppName = config.GetEnv("APP_NAME", defAppName) c.LoggerAddr = config.GetEnv("LOGGER_ADDR", defLoggerAddr) + c.RegistryAddr = config.GetEnv("REGISTRY_ADDR", defRegistryAddr) c.DbURL = config.GetEnv("DATABASE_URL", defDbURL) c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) c.EventBusExchange = ebEventsExchange c.EventBusQueue = ebEventsQueue + c.KVNamespace = config.GetEnv("APP_KV_NAMESPACE", defKVNmspc) logHost, logPort := fluentd.ParseAddr(c.LoggerAddr) logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) defer logger.Close() + consul, err := discovery.NewService(c.RegistryAddr, c.AppID, c.AppName, c.AppID, "", 0) + if err != nil { + logger.Log("Error connecting to %s: %v", c.RegistryAddr, err) + } + + go func(consul *discovery.Service) { + interval := time.Second * 3 + ticker := time.NewTicker(interval) + for range ticker.C { + err := updateKVConfig(consul, c) // FIXME: duplicated in internal/app/server/server.go + if err != nil { + logger.Log("KV config update error (skipping): %v\n", err) + } + } + }(consul) + // db conn dbConn, err := database.Connect(c.DbURL) if err != nil { // fixme: add wait-for-db... @@ -170,3 +195,22 @@ func main() { logger.Log("Waiting for messages...") <-forever } + +func updateKVConfig(s *discovery.Service, oldCnf *server.Config) error { // FIXME: duplicated in internal/app/server/server.go + data, _, err := s.KV().Get(oldCnf.KVNamespace, nil) + if err != nil { + return err + } + + if data == nil { + return errors.New("empty KV config data. Skipping") + } + + buf := bytes.NewBuffer(data.Value) + decoder := json.NewDecoder(buf) + if err := decoder.Decode(oldCnf); err != nil { + return err + } + + return nil +} diff --git a/src/go.mod b/src/go.mod index 93462be..8e0bf90 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,7 +3,7 @@ module git.pbiernat.dev/egommerce/basket-service go 1.18 require ( - git.pbiernat.dev/egommerce/go-api-pkg v0.0.101 + git.pbiernat.dev/egommerce/go-api-pkg v0.0.108 github.com/georgysavva/scany/v2 v2.0.0 github.com/gofiber/fiber/v2 v2.40.1 github.com/jackc/pgtype v1.12.0 diff --git a/src/go.sum b/src/go.sum index d9d9f5f..dfbdee8 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,13 +1,13 @@ -git.pbiernat.dev/egommerce/go-api-pkg v0.0.32 h1:ArB/n30m927WMAM4u51guH+qR0Lu4NGyYnYdi7OhlzY= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.32/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.33 h1:1tm+pvUeS6OZLvHmLM3BwFS0Ty/eA3jDRuB60OicosA= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.33/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.34 h1:UO1x6O+cyU7yYYbDCDyhhAypuf4QGIXcmWcBEEjLuYM= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.34/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.100 h1:jw4fiGbZTsfJXJpGV+HQiYeMGZ7DMRMoepjuIwY6FIU= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.100/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.101 h1:NZCFAAlC94+LcN1gjrENnWUHvpWgaNksyB2N4Fiy8C4= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.101/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.103 h1:tVSHVQOBDe1Ofcbodaa/R5gHRD4gYO/d1tw7rVuLJuA= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.103/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.104 h1:YymR7Zyo9xjIZ9S75o2nfyNHp69n2FXHyGbTxtV1p/A= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.104/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.105 h1:8w4p4QNaSF58iL3YiGvqXC4UjUVeeu5D10OQmImA/Z0= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.105/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.106 h1:kOqDvQfk8MzmyQonMMLmZKhW7I5YeDyw6N8YIYHIVwA= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.106/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.108 h1:gr5kzKNR3sCxTz+nbqtOM7vdIely5ZWb8itSLAjTo0I= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.108/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= diff --git a/src/internal/app/server/config.go b/src/internal/app/server/config.go index 9bec52b..9fce58d 100644 --- a/src/internal/app/server/config.go +++ b/src/internal/app/server/config.go @@ -3,18 +3,24 @@ package server import "fmt" type Config struct { - AppID string - AppName string - AppDomain string - NetAddr string - Port int - LoggerAddr string - RegistryAddr string - DbURL string - MongoDbUrl string - EventBusURL string - EventBusExchange string - EventBusQueue string + AppID string + AppName string + AppDomain string + NetAddr string + Port int + RegistryAddr string + KVNamespace string + + LoggerAddr string `json:"logger_addr"` + DbURL string `json:"db_url"` + MongoDbUrl string `json:"mongodb_url"` + EventBusURL string `json:"eventbus_url"` + EventBusExchange string `json:"eventbus_exchange"` + EventBusQueue string `json:"eventbus_queue"` + HttpReadTimeout int `json:"http_read_timeout"` + HttpWriteTimeout int `json:"http_write_timeout"` + HttpIdleTimeout int `json:"http_idle_timeout"` + // Fields with json mapping are available trough ConsulKV } func (c *Config) GetAppFullName() string { diff --git a/src/internal/app/server/health_handler.go b/src/internal/app/server/health_handler.go index 9ec6016..d62ee74 100644 --- a/src/internal/app/server/health_handler.go +++ b/src/internal/app/server/health_handler.go @@ -11,3 +11,7 @@ func (s *Server) HealthHandler(c *fiber.Ctx) error { Status: "OK", }) } + +func (s *Server) ConfigHandler(c *fiber.Ctx) error { + return c.JSON(s.conf) +} diff --git a/src/internal/app/server/router.go b/src/internal/app/server/router.go index 29e97ac..f738bfc 100644 --- a/src/internal/app/server/router.go +++ b/src/internal/app/server/router.go @@ -8,11 +8,12 @@ import ( ) func SetupRoutes(s *Server) { + s.App.Get("/health", s.HealthHandler) + s.App.Get("/config", s.ConfigHandler) + api := s.App.Group("/api") v1 := api.Group("/v1") v1.Post("/checkout", s.CheckoutHandler) - - s.App.Get("/health", s.HealthHandler) } func SetupMiddlewares(s *Server) { diff --git a/src/internal/app/server/server.go b/src/internal/app/server/server.go index 331cc2a..dd71400 100644 --- a/src/internal/app/server/server.go +++ b/src/internal/app/server/server.go @@ -1,6 +1,9 @@ package server import ( + "bytes" + "encoding/json" + "fmt" "os" "os/signal" "syscall" @@ -16,12 +19,14 @@ import ( type Server struct { *fiber.App + conf *Config log *fluentd.Logger db *pgxpool.Pool ebCh *amqp.Channel discovery *discovery.Service name string addr string + kvNmspc string } type Headers struct { @@ -30,13 +35,13 @@ type Headers struct { func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amqp.Channel) *Server { logger.Log("API_ID: %s", conf.AppID) - discovery, err := discovery.NewService(conf.RegistryAddr, conf.AppID, conf.AppName, conf.AppID, conf.AppDomain, conf.Port) + consul, err := discovery.NewService(conf.RegistryAddr, conf.AppID, conf.AppName, conf.AppID, conf.AppDomain, conf.Port) if err != nil { logger.Log("Error connecting to %s: %v", conf.RegistryAddr, err) } - logger.Log("Registering service with name: %s, address: %s", discovery.Name, discovery.Address) - err = discovery.Register() + logger.Log("Registering service with name: %s, address: %s", consul.Name, consul.Address) + err = consul.Register() if err != nil { logger.Log("register error: %v", err) } @@ -50,14 +55,27 @@ func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amq } s := &Server{ fiber.New(cnf), + conf, logger, db, ebCh, - discovery, + consul, conf.AppName, conf.NetAddr, + conf.KVNamespace, } + go func(s *Server) { // Consul KV config updater + interval := time.Second * 30 + ticker := time.NewTicker(interval) + for range ticker.C { + err := s.updateKVConfig() + if err != nil { + logger.Log("KV config update error (skipping): %v\n", err) + } + } + }(s) + SetupMiddlewares(s) SetupRoutes(s) @@ -98,6 +116,23 @@ func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) { return hdr.RequestID, nil } +func (s *Server) updateKVConfig() error { // FIXME: duplicated in cmd/worker/main.go + data, _, err := s.discovery.KV().Get(s.kvNmspc, nil) + if err != nil { + fmt.Println(err) + + return err + } + + kvCnf := bytes.NewBuffer(data.Value) + decoder := json.NewDecoder(kvCnf) + if err := decoder.Decode(&s.conf); err != nil { + return err + } + + return nil +} + func (s *Server) gracefulShutdown() error { s.log.Log("Server is going down...") s.log.Log("Unregistering service: %s", s.discovery.GetID()) From ec958071b2e14f78b4f8ad7a7aa07b1d3c13792c Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Wed, 7 Dec 2022 02:43:11 +0100 Subject: [PATCH 11/17] Added wait-for-it.sh script --- Dockerfile.target | 6 +- bin/entrypoint.sh | 25 +++++++ bin/wait-for-it.sh | 165 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 1 deletion(-) create mode 100755 bin/entrypoint.sh create mode 100755 bin/wait-for-it.sh diff --git a/Dockerfile.target b/Dockerfile.target index dd6760b..5dff45c 100644 --- a/Dockerfile.target +++ b/Dockerfile.target @@ -20,6 +20,10 @@ LABEL dev.egommerce.image.build_time=${BUILD_TIME} WORKDIR / COPY --from=builder $BIN_OUTPUT /app COPY .env.dist /.env +COPY ./bin/entrypoint.sh ./bin/wait-for-it.sh / +RUN chmod 755 /entrypoint.sh EXPOSE 80 -ENTRYPOINT ["/app"] + +CMD ["/app"] +ENTRYPOINT ["/entrypoint.sh"] diff --git a/bin/entrypoint.sh b/bin/entrypoint.sh new file mode 100755 index 0000000..f77e6fa --- /dev/null +++ b/bin/entrypoint.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env sh +set +e + +waitForService() +{ + ./wait-for-it.sh $1 -t 2 1>/dev/null 2>&1 + status=$? + while [ $status != 0 ] + do + echo "[x] wating for $1..." + sleep 1 + ./wait-for-it.sh $1 -t 2 1>/dev/null 2>&1 + status=$? + done +} + +waitForService "postgres-db:5432" +waitForService "api-eventbus:5672" +waitForService "api-logger:24224" +waitForService "api-registry:8500" + + +set -euo pipefail + +exec "$@" diff --git a/bin/wait-for-it.sh b/bin/wait-for-it.sh new file mode 100755 index 0000000..fff13c9 --- /dev/null +++ b/bin/wait-for-it.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env sh +# Use this script to test if a given TCP host/port are available + +set -e + +cmdname=$(basename "$0") + +echoerr() { + if [ "$QUIET" -ne 1 ]; then + printf "%s\n" "$*" 1>&2; + fi +} + +usage() +{ + exitcode="$1" + cat << USAGE >&2 +Usage: + $cmdname host:port [-s] [-t timeout] [-- command args] + -h HOST | --host=HOST Host or IP under test + -p PORT | --port=PORT TCP port under test + Alternatively, you specify the host and port as host:port + -s | --strict Only execute subcommand if the test succeeds + -q | --quiet Don't output any status messages + -t TIMEOUT | --timeout=TIMEOUT + Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit "$exitcode" +} + +wait_for() +{ + if [ "$TIMEOUT" -gt 0 ]; then + echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT" + else + echoerr "$cmdname: waiting for $HOST:$PORT without a timeout" + fi + start_ts=$(date +%s) + while true + do + nc -z "$HOST" "$PORT" >/dev/null 2>&1 + result=$? + if [ $result -eq 0 ]; then + end_ts=$(date +%s) + echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds" + break + fi + sleep 1 + done + return $result +} + +wait_for_wrapper() +{ + # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 + if [ "$QUIET" -eq 1 ]; then + timeout "$TIMEOUT" "$0" -q -child "$HOST":"$PORT" -t "$TIMEOUT" & + else + timeout "$TIMEOUT" "$0" --child "$HOST":"$PORT" -t "$TIMEOUT" & + fi + PID=$! + trap 'kill -INT -$PID' INT + wait $PID + RESULT=$? + if [ $RESULT -ne 0 ]; then + echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT" + fi + return $RESULT +} + +TIMEOUT=15 +STRICT=0 +CHILD=0 +QUIET=0 +# process arguments +while [ $# -gt 0 ] +do + case "$1" in + *:* ) + HOST=$(printf "%s\n" "$1"| cut -d : -f 1) + PORT=$(printf "%s\n" "$1"| cut -d : -f 2) + shift 1 + ;; + --child) + CHILD=1 + shift 1 + ;; + -q | --quiet) + QUIET=1 + shift 1 + ;; + -s | --strict) + STRICT=1 + shift 1 + ;; + -h) + HOST="$2" + if [ "$HOST" = "" ]; then break; fi + shift 2 + ;; + --host=*) + HOST=$(printf "%s" "$1" | cut -d = -f 2) + shift 1 + ;; + -p) + PORT="$2" + if [ "$PORT" = "" ]; then break; fi + shift 2 + ;; + --port=*) + PORT="${1#*=}" + shift 1 + ;; + -t) + TIMEOUT="$2" + if [ "$TIMEOUT" = "" ]; then break; fi + shift 2 + ;; + --timeout=*) + TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + break + ;; + --help) + usage 0 + ;; + *) + echoerr "Unknown argument: $1" + usage 1 + ;; + esac +done + +if [ "$HOST" = "" -o "$PORT" = "" ]; then + echoerr "Error: you need to provide a host and port to test." + usage 2 +fi + +if [ $CHILD -gt 0 ]; then + wait_for + RESULT=$? + exit $RESULT +else + if [ "$TIMEOUT" -gt 0 ]; then + wait_for_wrapper + RESULT=$? + else + wait_for + RESULT=$? + fi +fi + +if [ "$*" != "" ]; then + if [ $RESULT -ne 0 -a $STRICT -eq 1 ]; then + echoerr "$cmdname: strict mode, refusing to execute subprocess" + exit $RESULT + fi + exec "$@" +else + exit $RESULT +fi From 4f9e4f123346d8fe2ea3840413b7281890bc2f70 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Fri, 16 Dec 2022 01:03:40 +0100 Subject: [PATCH 12/17] fixes --- src/cmd/worker/main.go | 2 +- src/go.mod | 2 +- src/go.sum | 2 ++ src/internal/app/server/server.go | 9 +++++++-- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go index b3e3727..65a28aa 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -203,7 +203,7 @@ func updateKVConfig(s *discovery.Service, oldCnf *server.Config) error { // FIXM } if data == nil { - return errors.New("empty KV config data. Skipping") + return errors.New("empty KV config data") } buf := bytes.NewBuffer(data.Value) diff --git a/src/go.mod b/src/go.mod index 8e0bf90..20cc5db 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,7 +3,7 @@ module git.pbiernat.dev/egommerce/basket-service go 1.18 require ( - git.pbiernat.dev/egommerce/go-api-pkg v0.0.108 + git.pbiernat.dev/egommerce/go-api-pkg v0.0.113 github.com/georgysavva/scany/v2 v2.0.0 github.com/gofiber/fiber/v2 v2.40.1 github.com/jackc/pgtype v1.12.0 diff --git a/src/go.sum b/src/go.sum index dfbdee8..c10720a 100644 --- a/src/go.sum +++ b/src/go.sum @@ -8,6 +8,8 @@ git.pbiernat.dev/egommerce/go-api-pkg v0.0.106 h1:kOqDvQfk8MzmyQonMMLmZKhW7I5YeD git.pbiernat.dev/egommerce/go-api-pkg v0.0.106/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= git.pbiernat.dev/egommerce/go-api-pkg v0.0.108 h1:gr5kzKNR3sCxTz+nbqtOM7vdIely5ZWb8itSLAjTo0I= git.pbiernat.dev/egommerce/go-api-pkg v0.0.108/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.113 h1:kf7HesezhXIAMNYgLCm8x6YVqyLqJRqaPKIFEXf4xSs= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.113/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= diff --git a/src/internal/app/server/server.go b/src/internal/app/server/server.go index dd71400..bc1988e 100644 --- a/src/internal/app/server/server.go +++ b/src/internal/app/server/server.go @@ -3,6 +3,7 @@ package server import ( "bytes" "encoding/json" + "errors" "fmt" "os" "os/signal" @@ -117,14 +118,18 @@ func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) { } func (s *Server) updateKVConfig() error { // FIXME: duplicated in cmd/worker/main.go - data, _, err := s.discovery.KV().Get(s.kvNmspc, nil) + config, _, err := s.discovery.KV().Get(s.kvNmspc, nil) if err != nil { fmt.Println(err) return err } - kvCnf := bytes.NewBuffer(data.Value) + if config == nil { + return errors.New("empty KV config data") + } + + kvCnf := bytes.NewBuffer(config.Value) decoder := json.NewDecoder(kvCnf) if err := decoder.Decode(&s.conf); err != nil { return err From dca3a531fe32a428a40e4c8d7fe0a08bc87e6636 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Sat, 17 Dec 2022 08:11:05 +0100 Subject: [PATCH 13/17] Added migrations --- Dockerfile.builder | 2 + Dockerfile.target | 7 +- bin/entrypoint.sh | 8 +- bin/migrate.sh | 26 ++++++ src/cmd/migrate/main.go | 88 +++++++++++++++++++ src/cmd/worker/main.go | 5 +- src/go.mod | 10 +++ src/go.sum | 134 ++++++++++++++++++++++++++--- src/internal/app/server/server.go | 5 +- src/internal/app/service/basket.go | 6 +- 10 files changed, 264 insertions(+), 27 deletions(-) create mode 100644 bin/migrate.sh create mode 100644 src/cmd/migrate/main.go diff --git a/Dockerfile.builder b/Dockerfile.builder index 779d27f..6ccc27d 100644 --- a/Dockerfile.builder +++ b/Dockerfile.builder @@ -3,6 +3,7 @@ FROM golang:alpine ARG BIN_OUTPUT=/go/bin ARG GO_SERVER=cmd/server/main.go +ARG GO_MIGRATE=cmd/migrate/main.go ARG GO_WORKER=cmd/worker/main.go WORKDIR /go/src/app @@ -10,4 +11,5 @@ COPY src ./ RUN export CGO_ENABLED=0 ; export GOOS=linux ; export GOARCH=amd64 && \ go build -ldflags="-w -s" -o "$BIN_OUTPUT/server" $GO_SERVER && \ + go build -ldflags="-w -s" -o "$BIN_OUTPUT/migrate" $GO_MIGRATE && \ go build -ldflags="-w -s" -o "$BIN_OUTPUT/worker" $GO_WORKER diff --git a/Dockerfile.target b/Dockerfile.target index 5dff45c..944c9ce 100644 --- a/Dockerfile.target +++ b/Dockerfile.target @@ -19,11 +19,12 @@ LABEL dev.egommerce.image.build_time=${BUILD_TIME} WORKDIR / COPY --from=builder $BIN_OUTPUT /app +COPY --from=builder /go/bin/migrate /bin/go_migrate COPY .env.dist /.env -COPY ./bin/entrypoint.sh ./bin/wait-for-it.sh / -RUN chmod 755 /entrypoint.sh +COPY ./bin /bin +RUN chmod 755 /bin/entrypoint.sh /bin/migrate.sh EXPOSE 80 CMD ["/app"] -ENTRYPOINT ["/entrypoint.sh"] +ENTRYPOINT ["entrypoint.sh"] diff --git a/bin/entrypoint.sh b/bin/entrypoint.sh index f77e6fa..01a6dc9 100755 --- a/bin/entrypoint.sh +++ b/bin/entrypoint.sh @@ -3,13 +3,13 @@ set +e waitForService() { - ./wait-for-it.sh $1 -t 2 1>/dev/null 2>&1 + wait-for-it.sh $1 -t 2 1>/dev/null 2>&1 status=$? while [ $status != 0 ] do echo "[x] wating for $1..." sleep 1 - ./wait-for-it.sh $1 -t 2 1>/dev/null 2>&1 + wait-for-it.sh $1 -t 2 1>/dev/null 2>&1 status=$? done } @@ -19,7 +19,9 @@ waitForService "api-eventbus:5672" waitForService "api-logger:24224" waitForService "api-registry:8500" +# run migrations +migrate.sh -set -euo pipefail +# set -euo pipefail exec "$@" diff --git a/bin/migrate.sh b/bin/migrate.sh new file mode 100644 index 0000000..e2980b8 --- /dev/null +++ b/bin/migrate.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +# ensure migrate env is initialized +$(go_migrate version >/dev/null 2>&1) +version=$? +if [ $version != "0" ] +then + echo "Creating base table..." + $(go_migrate init >/dev/null 2>&1) + init=$? +fi + +# check again +$(go_migrate version >/dev/null 2>&1) +version=$? +if [ $version != "0" ] +then + echo "Unable to run migrations." + exit 1 +fi + +# run migrations +go_migrate up +echo "Done." + +exit $version diff --git a/src/cmd/migrate/main.go b/src/cmd/migrate/main.go new file mode 100644 index 0000000..8b0ad37 --- /dev/null +++ b/src/cmd/migrate/main.go @@ -0,0 +1,88 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + + "git.pbiernat.dev/egommerce/basket-service/internal/app/config" + "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" + "github.com/go-pg/migrations/v8" + "github.com/go-pg/pg/v10" +) + +const ( + defAppName = "basket-svc-migrations" + defMigrationsTableName = "basket.migrations" + defLoggerAddr = "api-logger:24224" + // defKVNmspc = "dev.egommerce/service/basket-migration" +) + +const usageText = `This program runs command on the db. Supported commands are: + - init - creates version info table in the database + - up - runs all available migrations. + - up [target] - runs available migrations up to the target one. + - down - reverts last migration. + - reset - reverts all migrations. + - version - prints current db version. + - set_version [version] - sets db version without running migrations. +Usage: + go run cmd/migrate/main.go [args] +` + +func main() { + if config.ErrLoadingEnvs != nil { + log.Panicln("Error loading .env file", config.ErrLoadingEnvs) + } + + // dbURL := config.GetEnv("DATABASE_URL", defDbURL) + loggerAddr := config.GetEnv("LOGGER_ADDR", defLoggerAddr) + mTblName := config.GetEnv("MIGRATIONS_TABLE_NAME", defMigrationsTableName) + + logHost, logPort := fluentd.ParseAddr(loggerAddr) + logger := fluentd.NewLogger(defAppName, logHost, logPort) + defer logger.Close() + + flag.Usage = usage + flag.Parse() + + db := pg.Connect(&pg.Options{ // FIXME + Addr: "postgres-db:5432", + User: "postgres", + Password: "12345678", + Database: "egommerce", + }) + + mig := migrations.NewCollection() + mig.SetTableName(mTblName) + err := mig.DiscoverSQLMigrations("./migrations") + if err != nil { + fmt.Println(err) + } + + oldVersion, newVersion, err := mig.Run(db, flag.Args()...) + if err != nil { + exitf(err.Error()) + } + if newVersion != oldVersion { + fmt.Printf("migrated from version %d to %d\n", oldVersion, newVersion) + } else { + fmt.Printf("version is %d\n", oldVersion) + } +} + +func usage() { + fmt.Print(usageText) + flag.PrintDefaults() + os.Exit(2) +} + +func errorf(s string, args ...interface{}) { + fmt.Fprintf(os.Stderr, s+"\n", args...) +} + +func exitf(s string, args ...interface{}) { + errorf(s, args...) + os.Exit(1) +} diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go index 65a28aa..d3b9711 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -64,10 +64,7 @@ func main() { interval := time.Second * 3 ticker := time.NewTicker(interval) for range ticker.C { - err := updateKVConfig(consul, c) // FIXME: duplicated in internal/app/server/server.go - if err != nil { - logger.Log("KV config update error (skipping): %v\n", err) - } + updateKVConfig(consul, c) // FIXME: duplicated in internal/app/server/server.go } }(consul) diff --git a/src/go.mod b/src/go.mod index 20cc5db..6d7392d 100644 --- a/src/go.mod +++ b/src/go.mod @@ -5,6 +5,8 @@ go 1.18 require ( git.pbiernat.dev/egommerce/go-api-pkg v0.0.113 github.com/georgysavva/scany/v2 v2.0.0 + github.com/go-pg/migrations/v8 v8.1.0 + github.com/go-pg/pg/v10 v10.10.7 github.com/gofiber/fiber/v2 v2.40.1 github.com/jackc/pgtype v1.12.0 github.com/jackc/pgx/v5 v5.1.1 @@ -17,6 +19,7 @@ require ( github.com/armon/go-metrics v0.4.1 // indirect github.com/fatih/color v1.13.0 // indirect github.com/fluent/fluent-logger-golang v1.9.0 // indirect + github.com/go-pg/zerochecker v0.2.0 // indirect github.com/hashicorp/consul/api v1.18.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.3.1 // indirect @@ -28,6 +31,7 @@ require ( github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect github.com/jackc/puddle/v2 v2.1.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect github.com/klauspost/compress v1.15.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect @@ -37,12 +41,18 @@ require ( github.com/philhofer/fwd v1.1.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/tinylib/msgp v1.1.6 // indirect + github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.41.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect + github.com/vmihailenco/bufpool v0.1.11 // indirect + github.com/vmihailenco/msgpack/v5 v5.3.4 // indirect + github.com/vmihailenco/tagparser v0.1.2 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect go.uber.org/atomic v1.10.0 // indirect golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect golang.org/x/sys v0.2.0 // indirect golang.org/x/text v0.3.8 // indirect + mellium.im/sasl v0.2.1 // indirect ) diff --git a/src/go.sum b/src/go.sum index c10720a..9a435e0 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,13 +1,4 @@ -git.pbiernat.dev/egommerce/go-api-pkg v0.0.103 h1:tVSHVQOBDe1Ofcbodaa/R5gHRD4gYO/d1tw7rVuLJuA= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.103/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.104 h1:YymR7Zyo9xjIZ9S75o2nfyNHp69n2FXHyGbTxtV1p/A= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.104/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.105 h1:8w4p4QNaSF58iL3YiGvqXC4UjUVeeu5D10OQmImA/Z0= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.105/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.106 h1:kOqDvQfk8MzmyQonMMLmZKhW7I5YeDyw6N8YIYHIVwA= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.106/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.108 h1:gr5kzKNR3sCxTz+nbqtOM7vdIely5ZWb8itSLAjTo0I= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.108/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= git.pbiernat.dev/egommerce/go-api-pkg v0.0.113 h1:kf7HesezhXIAMNYgLCm8x6YVqyLqJRqaPKIFEXf4xSs= git.pbiernat.dev/egommerce/go-api-pkg v0.0.113/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -30,9 +21,11 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -42,12 +35,17 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fluent/fluent-logger-golang v1.9.0 h1:zUdY44CHX2oIUc7VTNZc+4m+ORuO/mldQDA7czhWXEg= github.com/fluent/fluent-logger-golang v1.9.0/go.mod h1:2/HCT/jTy78yGyeNGQLGQsjF3zzzAuy6Xlk6FCMV5eU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/georgysavva/scany/v2 v2.0.0 h1:RGXqxDv4row7/FYoK8MRXAZXqoWF/NM+NP0q50k3DKU= github.com/georgysavva/scany/v2 v2.0.0/go.mod h1:sigOdh+0qb/+aOs3TVhehVT10p8qJL7K/Zhyz8vWo38= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -56,19 +54,42 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-pg/migrations/v8 v8.1.0 h1:bc1wQwFoWRKvLdluXCRFRkeaw9xDU4qJ63uCAagh66w= +github.com/go-pg/migrations/v8 v8.1.0/go.mod h1:o+CN1u572XHphEHZyK6tqyg2GDkRvL2bIoLNyGIewus= +github.com/go-pg/pg/v10 v10.4.0/go.mod h1:BfgPoQnD2wXNd986RYEHzikqv9iE875PrFaZ9vXvtNM= +github.com/go-pg/pg/v10 v10.10.7 h1:Q7Bs45kP9MIg03v/ejwdqsPd1T0cecgeDoTJVg/UJuQ= +github.com/go-pg/pg/v10 v10.10.7/go.mod h1:GLmFXufrElQHf5uzM3BQlcfwV3nsgnHue5uzjQ6Nqxg= +github.com/go-pg/zerochecker v0.2.0 h1:pp7f72c3DobMWOb2ErtZsnrPaSvHd2W4o9//8HtF4mU= +github.com/go-pg/zerochecker v0.2.0/go.mod h1:NJZ4wKL0NmTtz0GKCoJ8kym6Xn/EQzXRl2OnAe7MmDo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofiber/fiber/v2 v2.40.1 h1:pc7n9VVpGIqNsvg9IPLQhyFEMJL8gCs1kneH5D1pIl4= github.com/gofiber/fiber/v2 v2.40.1/go.mod h1:Gko04sLksnHbzLSRBFWPFdzM9Ws9pRxvvIaohJK1dsk= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -116,6 +137,7 @@ github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= @@ -164,6 +186,8 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle/v2 v2.1.2 h1:0f7vaaXINONKTsxYDn4otOAiJanX/BMeAtY//BXqzlg= github.com/jackc/puddle/v2 v2.1.2/go.mod h1:2lpufsF5mRHO6SuZkm0fNYxM6SWHfvyFj62KwNzgels= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -227,6 +251,17 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= +github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -245,6 +280,7 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= @@ -278,11 +314,14 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/tinylib/msgp v1.1.6 h1:i+SbKraHhnrf9M5MYmvQhFnbLhAXSDWF8WWsuyRdocw= github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -290,8 +329,20 @@ github.com/valyala/fasthttp v1.41.0 h1:zeR0Z1my1wDHTRiamBCXVglQdbUwgb9uWG3k1HQz6 github.com/valyala/fasthttp v1.41.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/vmihailenco/bufpool v0.1.11 h1:gOq2WmBrq0i2yW5QJ16ykccQ4wH9UyEsgLm6czKAd94= +github.com/vmihailenco/bufpool v0.1.11/go.mod h1:AFf/MOy3l2CFTKbxwt0mp2MwnqjNEs5H/UxrkA5jxTQ= +github.com/vmihailenco/msgpack/v4 v4.3.11/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= +github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1/go.mod h1:xlngVLeyQ/Qi05oQxhQ+oTuqa03RjMwMfk/7/TCs+QI= +github.com/vmihailenco/msgpack/v5 v5.3.4 h1:qMKAwOV+meBw2Y8k9cVwAy7qErtYCwBzZ2ellBfvnqc= +github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc= +github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -306,6 +357,7 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -313,23 +365,40 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= @@ -337,6 +406,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo= golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -346,7 +417,9 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc= golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -354,20 +427,28 @@ golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201017003518-b09fb700fbb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -387,8 +468,11 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -404,18 +488,48 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +mellium.im/sasl v0.2.1 h1:nspKSRg7/SyO0cRGY71OkfHab8tf9kCts6a6oTDut0w= +mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ= diff --git a/src/internal/app/server/server.go b/src/internal/app/server/server.go index bc1988e..f443551 100644 --- a/src/internal/app/server/server.go +++ b/src/internal/app/server/server.go @@ -70,10 +70,7 @@ func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amq interval := time.Second * 30 ticker := time.NewTicker(interval) for range ticker.C { - err := s.updateKVConfig() - if err != nil { - logger.Log("KV config update error (skipping): %v\n", err) - } + s.updateKVConfig() } }(s) diff --git a/src/internal/app/service/basket.go b/src/internal/app/service/basket.go index 233da06..67d17b1 100644 --- a/src/internal/app/service/basket.go +++ b/src/internal/app/service/basket.go @@ -25,7 +25,7 @@ func NewBasketService(dbConn *pgxpool.Pool, chn *base.Channel, log *fluentd.Logg func (s *BasketService) Create(basketID string) (*def.BasketModel, error) { ctx := context.Background() - sql := `INSERT INTO "basket-svc".basket(id) VALUES($1)` + sql := `INSERT INTO basket.basket(id) VALUES($1)` if _, err := s.dbConn.Exec(ctx, sql, basketID); err != nil { return nil, err } @@ -37,7 +37,7 @@ func (s *BasketService) FetchFromDB(basketID string) (*def.BasketModel, error) { ctx := context.Background() basket := new(def.BasketModel) - err := pgxscan.Get(ctx, s.dbConn, basket, `SELECT id, created_at, updated_at FROM "basket-svc".basket WHERE id=$1`, basketID) + err := pgxscan.Get(ctx, s.dbConn, basket, `SELECT id, created_at, updated_at FROM basket.basket WHERE id=$1`, basketID) if err != nil { return nil, err } @@ -49,7 +49,7 @@ func (s *BasketService) AddProduct(productId, basketID string, qty int) error { ctx := context.Background() s.log.Log("Adding product#:%s into Basket#:%s", productId, basketID) - sql := `INSERT INTO "basket-svc".basket_item(basket_id, product_id) VALUES($1,$2)` + sql := `INSERT INTO basket.basket_item(basket_id, product_id) VALUES($1,$2)` if _, err := s.dbConn.Exec(ctx, sql, basketID, productId); err != nil { return err } From 9c74b911c3b9f10ef72edd25f64fb066412a6ee9 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Sun, 25 Dec 2022 21:05:44 +0100 Subject: [PATCH 14/17] Refactoring --- Dockerfile.target | 6 +- bin/entrypoint.sh | 1 + src/cmd/migrate/main.go | 18 +-- src/cmd/server/main.go | 17 ++- src/cmd/worker/main.go | 117 +++++++++++--------- src/go.mod | 8 +- src/go.sum | 26 +++-- src/internal/app/definition/basket_http.go | 9 -- src/internal/app/definition/basket_model.go | 13 --- src/internal/app/definition/error.go | 9 -- src/internal/app/definition/health_http.go | 5 - src/internal/app/server/basket_handler.go | 84 +++++++++++--- src/internal/app/server/config.go | 3 + src/internal/app/server/health_handler.go | 2 +- src/internal/app/server/router.go | 25 +++++ src/internal/app/server/server.go | 66 ++++++++--- src/internal/app/service/basket.go | 108 ++++++++++++++---- src/internal/app/ui/basket.go | 88 +++++++++++++++ 18 files changed, 437 insertions(+), 168 deletions(-) delete mode 100644 src/internal/app/definition/basket_http.go delete mode 100644 src/internal/app/definition/basket_model.go delete mode 100644 src/internal/app/definition/error.go delete mode 100644 src/internal/app/definition/health_http.go create mode 100644 src/internal/app/ui/basket.go diff --git a/Dockerfile.target b/Dockerfile.target index 944c9ce..decc891 100644 --- a/Dockerfile.target +++ b/Dockerfile.target @@ -6,10 +6,10 @@ FROM ${BUILDER_IMAGE} AS builder # FROM gcr.io/distroless/base-debian10 FROM alpine:3.17 -ARG BUILD_TIME -ARG BIN_OUTPUT ARG SVC_NAME ARG SVC_VER +ARG BIN_OUTPUT +ARG BUILD_TIME LABEL dev.egommerce.image.author="Piotr Biernat" LABEL dev.egommerce.image.vendor="Egommerce" @@ -26,5 +26,5 @@ RUN chmod 755 /bin/entrypoint.sh /bin/migrate.sh EXPOSE 80 -CMD ["/app"] +CMD ["sh", "-c", "/app"] ENTRYPOINT ["entrypoint.sh"] diff --git a/bin/entrypoint.sh b/bin/entrypoint.sh index 01a6dc9..5615ef8 100755 --- a/bin/entrypoint.sh +++ b/bin/entrypoint.sh @@ -18,6 +18,7 @@ waitForService "postgres-db:5432" waitForService "api-eventbus:5672" waitForService "api-logger:24224" waitForService "api-registry:8500" +waitForService "pricing-svc:80" # run migrations migrate.sh diff --git a/src/cmd/migrate/main.go b/src/cmd/migrate/main.go index 8b0ad37..fecaf60 100644 --- a/src/cmd/migrate/main.go +++ b/src/cmd/migrate/main.go @@ -58,17 +58,18 @@ func main() { mig.SetTableName(mTblName) err := mig.DiscoverSQLMigrations("./migrations") if err != nil { - fmt.Println(err) + logger.Log("migration dicovery error: %#v", err) } oldVersion, newVersion, err := mig.Run(db, flag.Args()...) if err != nil { - exitf(err.Error()) + logger.Log("migration runner error: %#v", err) + os.Exit(1) } if newVersion != oldVersion { - fmt.Printf("migrated from version %d to %d\n", oldVersion, newVersion) + logger.Log("migrated from version %d to %d\n", oldVersion, newVersion) } else { - fmt.Printf("version is %d\n", oldVersion) + logger.Log("version is %d\n", oldVersion) } } @@ -77,12 +78,3 @@ func usage() { flag.PrintDefaults() os.Exit(2) } - -func errorf(s string, args ...interface{}) { - fmt.Fprintf(os.Stderr, s+"\n", args...) -} - -func exitf(s string, args ...interface{}) { - errorf(s, args...) - os.Exit(1) -} diff --git a/src/cmd/server/main.go b/src/cmd/server/main.go index 163eb3e..83d60ff 100644 --- a/src/cmd/server/main.go +++ b/src/cmd/server/main.go @@ -10,15 +10,19 @@ import ( "git.pbiernat.dev/egommerce/basket-service/internal/app/server" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" + "github.com/go-redis/redis/v8" ) const ( defAppName = "basket-svc" defAppDomain = "basket-svc" + defPathPrefix = "/basket" defNetAddr = ":80" defLoggerAddr = "api-logger:24224" defRegistryAddr = "api-registry:8500" defDbURL = "postgres://postgres:12345678@postgres-db:5432/egommerce" + defCacheAddr = "api-cache:6379" + defCachePassword = "12345678" defMongoDbURL = "mongodb://mongodb:12345678@mongo-db:27017" defEventBusURL = "amqp://guest:guest@api-eventbus:5672" ebEventsExchange = "api-events" @@ -35,11 +39,14 @@ func main() { c.AppID, _ = os.Hostname() c.AppName = config.GetEnv("APP_NAME", defAppName) c.AppDomain = config.GetEnv("APP_DOMAIN", defAppDomain) + c.PathPrefix = config.GetEnv("APP_PATH_PREFIX", defPathPrefix) c.NetAddr = config.GetEnv("SERVER_ADDR", defNetAddr) c.Port, _ = strconv.Atoi(c.NetAddr[1:]) c.LoggerAddr = config.GetEnv("LOGGER_ADDR", defLoggerAddr) c.RegistryAddr = config.GetEnv("REGISTRY_ADDR", defRegistryAddr) c.DbURL = config.GetEnv("DATABASE_URL", defDbURL) + c.CacheAddr = config.GetEnv("CACHE_ADDR", defCacheAddr) + c.CachePassword = config.GetEnv("CACHE_PASSWORD", defCachePassword) c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) c.EventBusExchange = ebEventsExchange c.KVNamespace = config.GetEnv("APP_KV_NAMESPACE", defKVNmspc) @@ -56,6 +63,14 @@ func main() { } defer dbConn.Close() + // redis conn + redis := redis.NewClient(&redis.Options{ + Addr: c.CacheAddr, + Password: c.CachePassword, + DB: 0, + }) + defer redis.Close() + // eventbus conn ebConn, ebCh, err := amqp.Open(c.EventBusURL) if err != nil { @@ -72,7 +87,7 @@ func main() { } // start server - srv := server.NewServer(c, logger, dbConn, ebCh) + srv := server.NewServer(c, logger, dbConn, redis, ebCh) forever := make(chan struct{}) srv.StartWithGracefulShutdown(forever) diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go index d3b9711..6bc2717 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -14,13 +14,15 @@ import ( "git.pbiernat.dev/egommerce/basket-service/internal/app/config" "git.pbiernat.dev/egommerce/basket-service/internal/app/database" - def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" "git.pbiernat.dev/egommerce/basket-service/internal/app/event" "git.pbiernat.dev/egommerce/basket-service/internal/app/server" "git.pbiernat.dev/egommerce/basket-service/internal/app/service" + "git.pbiernat.dev/egommerce/basket-service/internal/app/ui" discovery "git.pbiernat.dev/egommerce/go-api-pkg/consul" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" - amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" + "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" + "github.com/go-redis/redis/v8" + "github.com/streadway/amqp" ) const ( @@ -28,6 +30,8 @@ const ( defLoggerAddr = "api-logger:24224" defRegistryAddr = "api-registry:8500" defDbURL = "postgres://postgres:12345678@postgres-db:5432/egommerce" + defCacheAddr = "api-cache:6379" + defCachePassword = "12345678" defMongoDbURL = "mongodb://mongodb:12345678@mongo-db:27017" defEventBusURL = "amqp://guest:guest@api-eventbus:5672" ebEventsExchange = "api-events" @@ -46,6 +50,8 @@ func main() { c.LoggerAddr = config.GetEnv("LOGGER_ADDR", defLoggerAddr) c.RegistryAddr = config.GetEnv("REGISTRY_ADDR", defRegistryAddr) c.DbURL = config.GetEnv("DATABASE_URL", defDbURL) + c.CacheAddr = config.GetEnv("CACHE_ADDR", defCacheAddr) + c.CachePassword = config.GetEnv("CACHE_PASSWORD", defCachePassword) c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) c.EventBusExchange = ebEventsExchange c.EventBusQueue = ebEventsQueue @@ -55,7 +61,7 @@ func main() { logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) defer logger.Close() - consul, err := discovery.NewService(c.RegistryAddr, c.AppID, c.AppName, c.AppID, "", 0) + consul, err := discovery.NewService(c.RegistryAddr, c.AppID, c.AppName, c.AppID, "", "", 0) if err != nil { logger.Log("Error connecting to %s: %v", c.RegistryAddr, err) } @@ -76,16 +82,24 @@ func main() { } defer dbConn.Close() + // redis conn + redis := redis.NewClient(&redis.Options{ + Addr: c.CacheAddr, + Password: c.CachePassword, + DB: 0, + }) + defer redis.Close() + // eventbus conn - ebConn, ebCh, err := amqp.Open(c.EventBusURL) + ebConn, ebCh, err := rabbitmq.Open(c.EventBusURL) if err != nil { logger.Log("Failed to connect to EventBus server: %v\n", err) os.Exit(1) } defer ebCh.Close() - defer amqp.Close(ebConn) + defer rabbitmq.Close(ebConn) - err = amqp.NewExchange(ebCh, c.EventBusExchange) + err = rabbitmq.NewExchange(ebCh, c.EventBusExchange) if err != nil { logger.Log("Failed to declare EventBus exchange: %v\n", err) os.Exit(1) @@ -105,14 +119,9 @@ func main() { os.Exit(1) } - amqp.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "catalog.basket.productAddedToBasket") - amqp.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "catalog.basket.productRemovedFromBasket") - amqp.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "catalog.basket.updateQuantity") - // err = amqp.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "catalog-svc.product.addedToBasket") - // if err != nil { - // logger.Log("Failed to prepare EventBus queue: %v\n", err) - // os.Exit(1) - // } + rabbitmq.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "catalog.basket.productAddedToBasket") + rabbitmq.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "catalog.basket.productRemovedFromBasket") + rabbitmq.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "catalog.basket.updateQuantity") // event consume msgs, err := ebCh.Consume( @@ -141,51 +150,55 @@ func main() { }() go func() { - bSrvc := service.NewBasketService(dbConn, ebCh, logger) + basketSrv := service.NewBasketService(dbConn, redis, ebCh, logger) for d := range msgs { - msg, err := amqp.Deserialize(d.Body) - if err != nil { - logger.Log("json error: %v\n", err) - d.Reject(false) // FIXME: how to handle erros in queue...???? - continue - } - - eName := fmt.Sprintf("%s", msg["event"]) - data := (msg["data"]).(map[string]interface{}) - logger.Log("Message<%s>: %s\n", eName, data) - - basketID := data["basket_id"].(string) // FIXME Check input params! - productID := data["product_id"].(string) // FIXME Check input params! - - switch true { - case strings.Contains(eName, event.EVENT_PRODUCT_ADDED_TO_BASKET): - var basket *def.BasketModel - basket, err := bSrvc.FetchFromDB(basketID) + go func(d amqp.Delivery) { + msg, err := rabbitmq.Deserialize(d.Body) if err != nil { - logger.Log("Basket#:%s not found. Creating...", basketID) - basket, err = bSrvc.Create(basketID) + logger.Log("deserialize error: %v\n", err) + d.Reject(false) // FIXME: or Nack? how to handle erros in queue... + return + } + + eName := fmt.Sprintf("%s", msg["event"]) + data := (msg["data"]).(map[string]interface{}) + logger.Log("Message<%s>: %v\n", eName, data) + + reqID := data["request_id"].(string) // FIXME Check input params! + basketID := data["basket_id"].(string) // FIXME Check input params! + + switch true { + case strings.Contains(eName, event.EVENT_PRODUCT_ADDED_TO_BASKET): + productID := int(data["product_id"].(float64)) + qty := int(data["quantity"].(float64)) + + basket, err := ui.AddProductToBasket(basketSrv, productID, qty, basketID, reqID) if err != nil { - logger.Log("Creating basket error: %v", err) - d.Reject(false) - continue + fmt.Println("worker error: ", err) + logger.Log("%s error: %s", event.EVENT_PRODUCT_ADDED_TO_BASKET, err.Error()) + d.Reject(false) // FIXME: or Nack? how to handle erros in queue... + break } + + logger.Log("Product #%s added to basket #%s. ReqID: #%s", productID, basket.ID, reqID) + case strings.Contains(eName, event.EVENT_PRODUCT_REMOVED_FROM_BASKET): + productID := int(data["product_id"].(float64)) + qty := int(data["quantity"].(float64)) + + basket, err := ui.RemoveProductFromBasket(basketSrv, productID, qty, basketID, reqID) + if err != nil { + logger.Log("%s error: %s", event.EVENT_PRODUCT_ADDED_TO_BASKET, err.Error()) + d.Reject(false) // FIXME: or Nack? how to handle erros in queue... + break + } + + logger.Log("Product #%s removed from basket #%s. ReqID: #%s", productID, basket.ID, reqID) } - err = bSrvc.AddProduct(productID, basketID, 1) // FIXME: change to Update quantity - which add or delete product to/from basket depends on new quantity - if err != nil { - logger.Log("Error adding product to basket: %v", err) - d.Reject(false) - } - logger.Log("Fetched basket: %v", basket) - - case strings.Contains(eName, event.EVENT_PRODUCT_REMOVED_FROM_BASKET): - // remove product from basket - logger.Log("Event: %s", event.EVENT_PRODUCT_REMOVED_FROM_BASKET) - } - - logger.Log("ACK: %s", eName) - d.Ack(false) + logger.Log("ACK: %s", eName) + d.Ack(false) + }(d) } }() diff --git a/src/go.mod b/src/go.mod index 6d7392d..4bb84ca 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,12 +3,13 @@ module git.pbiernat.dev/egommerce/basket-service go 1.18 require ( - git.pbiernat.dev/egommerce/go-api-pkg v0.0.113 + git.pbiernat.dev/egommerce/api-entities v0.0.26 + git.pbiernat.dev/egommerce/go-api-pkg v0.0.136 github.com/georgysavva/scany/v2 v2.0.0 github.com/go-pg/migrations/v8 v8.1.0 github.com/go-pg/pg/v10 v10.10.7 + github.com/go-redis/redis/v8 v8.11.5 github.com/gofiber/fiber/v2 v2.40.1 - github.com/jackc/pgtype v1.12.0 github.com/jackc/pgx/v5 v5.1.1 github.com/joho/godotenv v1.4.0 github.com/streadway/amqp v1.0.0 @@ -17,6 +18,8 @@ require ( require ( github.com/andybalholm/brotli v1.0.4 // indirect github.com/armon/go-metrics v0.4.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.13.0 // indirect github.com/fluent/fluent-logger-golang v1.9.0 // indirect github.com/go-pg/zerochecker v0.2.0 // indirect @@ -30,6 +33,7 @@ require ( github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect + github.com/jackc/pgtype v1.13.0 // indirect github.com/jackc/puddle/v2 v2.1.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/klauspost/compress v1.15.9 // indirect diff --git a/src/go.sum b/src/go.sum index 9a435e0..505f01a 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,6 +1,10 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.113 h1:kf7HesezhXIAMNYgLCm8x6YVqyLqJRqaPKIFEXf4xSs= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.113/go.mod h1:nAwcw2MZtn/54YKq8VQK6RJAsiuoLUtPuazXg8JcqK8= +git.pbiernat.dev/egommerce/api-entities v0.0.26 h1:Avz02GINwuYWOjw1fmZIJ3QgGEIz3a5vRQZNaxxUQIk= +git.pbiernat.dev/egommerce/api-entities v0.0.26/go.mod h1:+BXvUcr6Cr6QNpJsW8BUfe1vVILdWDADNE0e3u0lNvU= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.135 h1:qOa6MB6d2/lr0t9c3WWP84rf/T57PNYgizTmuNCDws8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.135/go.mod h1:w2N79aoumjrrcrGPJLkCwxAHtrLd7G4Uj8VOxvPooa0= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.136 h1:SzJRAkqJKdng/3d0V7o/R0yGh7QaZynPBn/P++on9RA= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.136/go.mod h1:w2N79aoumjrrcrGPJLkCwxAHtrLd7G4Uj8VOxvPooa0= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -23,6 +27,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -35,6 +41,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -61,6 +69,8 @@ github.com/go-pg/pg/v10 v10.10.7 h1:Q7Bs45kP9MIg03v/ejwdqsPd1T0cecgeDoTJVg/UJuQ= github.com/go-pg/pg/v10 v10.10.7/go.mod h1:GLmFXufrElQHf5uzM3BQlcfwV3nsgnHue5uzjQ6Nqxg= github.com/go-pg/zerochecker v0.2.0 h1:pp7f72c3DobMWOb2ErtZsnrPaSvHd2W4o9//8HtF4mU= github.com/go-pg/zerochecker v0.2.0/go.mod h1:NJZ4wKL0NmTtz0GKCoJ8kym6Xn/EQzXRl2OnAe7MmDo= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofiber/fiber/v2 v2.40.1 h1:pc7n9VVpGIqNsvg9IPLQhyFEMJL8gCs1kneH5D1pIl4= github.com/gofiber/fiber/v2 v2.40.1/go.mod h1:Gko04sLksnHbzLSRBFWPFdzM9Ws9pRxvvIaohJK1dsk= @@ -172,8 +182,8 @@ github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01C github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.13.0 h1:XkIc7A+1BmZD19bB2NxrtjJweHxQ9agqvM+9URc68Cg= +github.com/jackc/pgtype v1.13.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= @@ -252,16 +262,16 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -523,8 +533,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/src/internal/app/definition/basket_http.go b/src/internal/app/definition/basket_http.go deleted file mode 100644 index 001c4dc..0000000 --- a/src/internal/app/definition/basket_http.go +++ /dev/null @@ -1,9 +0,0 @@ -package definition - -type BasketCheckoutRequest struct { - BasketID string `json:"basket_id"` -} - -type BasketCheckoutResponse struct { - ID string `json:"order_id"` -} diff --git a/src/internal/app/definition/basket_model.go b/src/internal/app/definition/basket_model.go deleted file mode 100644 index 232d622..0000000 --- a/src/internal/app/definition/basket_model.go +++ /dev/null @@ -1,13 +0,0 @@ -package definition - -import ( - "time" - - "github.com/jackc/pgtype" -) - -type BasketModel struct { - ID string `db:"id"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt pgtype.Timestamp `db:"updated_at"` -} diff --git a/src/internal/app/definition/error.go b/src/internal/app/definition/error.go deleted file mode 100644 index 28f7dbf..0000000 --- a/src/internal/app/definition/error.go +++ /dev/null @@ -1,9 +0,0 @@ -package definition - -type ErrorResponse struct { - Error string `json:"error"` -} - -func Error(err string) *ErrorResponse { - return &ErrorResponse{err} -} diff --git a/src/internal/app/definition/health_http.go b/src/internal/app/definition/health_http.go deleted file mode 100644 index 6920fca..0000000 --- a/src/internal/app/definition/health_http.go +++ /dev/null @@ -1,5 +0,0 @@ -package definition - -type HealthResponse struct { - Status string `json:"status,omitempty"` -} diff --git a/src/internal/app/server/basket_handler.go b/src/internal/app/server/basket_handler.go index 24c71e7..f4f3e6a 100644 --- a/src/internal/app/server/basket_handler.go +++ b/src/internal/app/server/basket_handler.go @@ -1,24 +1,82 @@ package server import ( - def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" + "context" + "time" + + def "git.pbiernat.dev/egommerce/api-entities/http" "git.pbiernat.dev/egommerce/basket-service/internal/app/service" + "git.pbiernat.dev/egommerce/basket-service/internal/app/ui" "github.com/gofiber/fiber/v2" ) -func (s *Server) CheckoutHandler(c *fiber.Ctx) error { - reqID, _ := s.GetRequestID(c) - data := new(def.BasketCheckoutRequest) - if err := c.BodyParser(data); err != nil { - return err +func (s *Server) GetBasketHandler(c *fiber.Ctx) error { + req := new(def.GetBasketRequest) + if err := c.BodyParser(req); err != nil { + return s.Error400(c, err.Error()) } - basketID := data.BasketID - // vlaidate, pre check... etc - basket := service.NewBasketService(s.db, s.ebCh, s.log) - basket.Checkout(reqID, basketID) + basketID := req.BasketID + basketSrv := service.NewBasketService(s.db, s.cache, s.ebCh, s.log) + ctx := context.Background() + basket, err := basketSrv.FetchFromDB(ctx, basketID) + if err != nil { + return s.Error400(c, "Failed to retrieve basket") + } - return c.JSON(&def.BasketCheckoutResponse{ - ID: data.BasketID, - }) + res := &def.GetBasketResponse{ + ID: basket.ID, + State: basket.State, + CreatedAt: time.Duration(basket.CreatedAt.Time.Unix()), + } + if basket.UpdatedAt.Time.Unix() > 0 { + res.UpdatedAt = time.Duration(basket.UpdatedAt.Time.Unix()) + } + + return c.JSON(res) +} + +func (s *Server) GetBasketItemsHandler(c *fiber.Ctx) error { + basketID := c.Params("basketId", "") + basketSrv := service.NewBasketService(s.db, s.cache, s.ebCh, s.log) + ctx := context.Background() + items, err := basketSrv.FetchItems(ctx, basketID) + if err != nil { + return s.Error400(c, "Failed to retrieve basket items") + } + + var res []*def.GetBasketItemsResponse // FIXME + for _, item := range items { + resItem := &def.GetBasketItemsResponse{ + ID: item.ID, + BasketID: item.BasketID, + ProductID: item.ProductID, + Quantity: item.Quantity, + Price: item.Price, + CreatedAt: time.Duration(item.CreatedAt.Time.Unix()), + } + if item.UpdatedAt.Time.Unix() > 0 { + resItem.UpdatedAt = time.Duration(item.UpdatedAt.Time.Unix()) + } + res = append(res, resItem) + } + + return c.JSON(res) +} + +func (s *Server) CheckoutHandler(c *fiber.Ctx) error { + reqID, _ := s.GetRequestID(c) + req := new(def.BasketCheckoutRequest) + if err := c.BodyParser(req); err != nil { + return s.Error400(c, err.Error()) + } + + basketID := req.BasketID + basketSrv := service.NewBasketService(s.db, s.cache, s.ebCh, s.log) + res, err := ui.CheckoutBasket(basketSrv, basketID, reqID) + if err != nil { + return s.Error400(c, "Failed to create order") + } + + return c.JSON(res) } diff --git a/src/internal/app/server/config.go b/src/internal/app/server/config.go index 9fce58d..5213283 100644 --- a/src/internal/app/server/config.go +++ b/src/internal/app/server/config.go @@ -6,6 +6,7 @@ type Config struct { AppID string AppName string AppDomain string + PathPrefix string NetAddr string Port int RegistryAddr string @@ -13,6 +14,8 @@ type Config struct { LoggerAddr string `json:"logger_addr"` DbURL string `json:"db_url"` + CacheAddr string `json:"cache_addr"` + CachePassword string `json:"cache_password"` MongoDbUrl string `json:"mongodb_url"` EventBusURL string `json:"eventbus_url"` EventBusExchange string `json:"eventbus_exchange"` diff --git a/src/internal/app/server/health_handler.go b/src/internal/app/server/health_handler.go index d62ee74..73d756e 100644 --- a/src/internal/app/server/health_handler.go +++ b/src/internal/app/server/health_handler.go @@ -3,7 +3,7 @@ package server import ( "github.com/gofiber/fiber/v2" - def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" + def "git.pbiernat.dev/egommerce/api-entities/http" ) func (s *Server) HealthHandler(c *fiber.Ctx) error { diff --git a/src/internal/app/server/router.go b/src/internal/app/server/router.go index f738bfc..38cb6aa 100644 --- a/src/internal/app/server/router.go +++ b/src/internal/app/server/router.go @@ -1,25 +1,50 @@ package server import ( + "net/http" "strings" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/cors" +) + +var ( + defaultCORS = cors.New(cors.Config{ + AllowOrigins: "*", + AllowCredentials: true, + AllowMethods: "GET, POST, PATCH, PUT, DELETE, OPTIONS", + AllowHeaders: "Accept, Authorization, Content-Type, Vary, X-Request-Id", + }) ) func SetupRoutes(s *Server) { + s.App.Options("*", defaultCORS) + s.App.Get("/health", s.HealthHandler) s.App.Get("/config", s.ConfigHandler) api := s.App.Group("/api") v1 := api.Group("/v1") + v1.Get("/basket", s.GetBasketHandler) + v1.Get("/basket/:basketId/items", s.GetBasketItemsHandler) v1.Post("/checkout", s.CheckoutHandler) } func SetupMiddlewares(s *Server) { + s.App.Use(defaultCORS) s.App.Use(LoggingMiddleware(s.log)) } +func CORSPreflightMiddleware(c *fiber.Ctx) error { + if string(c.Request().Header.Method()) == http.MethodOptions { + c.Response().SetStatusCode(http.StatusOK) + c.Next() + } + + return c.Next() +} + // Middlewares func LoggingMiddleware(log *fluentd.Logger) func(c *fiber.Ctx) error { return func(c *fiber.Ctx) error { diff --git a/src/internal/app/server/server.go b/src/internal/app/server/server.go index f443551..ef406e9 100644 --- a/src/internal/app/server/server.go +++ b/src/internal/app/server/server.go @@ -2,18 +2,19 @@ package server import ( "bytes" + "context" "encoding/json" - "errors" - "fmt" "os" "os/signal" "syscall" "time" + "github.com/go-redis/redis/v8" "github.com/gofiber/fiber/v2" "github.com/jackc/pgx/v5/pgxpool" "github.com/streadway/amqp" + def "git.pbiernat.dev/egommerce/api-entities/http" discovery "git.pbiernat.dev/egommerce/go-api-pkg/consul" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" ) @@ -23,6 +24,7 @@ type Server struct { conf *Config log *fluentd.Logger db *pgxpool.Pool + cache *redis.Client ebCh *amqp.Channel discovery *discovery.Service name string @@ -34,9 +36,8 @@ type Headers struct { RequestID string `reqHeader:"x-request-id"` } -func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amqp.Channel) *Server { - logger.Log("API_ID: %s", conf.AppID) - consul, err := discovery.NewService(conf.RegistryAddr, conf.AppID, conf.AppName, conf.AppID, conf.AppDomain, conf.Port) +func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, cache *redis.Client, ebCh *amqp.Channel) *Server { + consul, err := discovery.NewService(conf.RegistryAddr, conf.AppID, conf.AppName, conf.AppID, conf.AppDomain, conf.PathPrefix, conf.Port) if err != nil { logger.Log("Error connecting to %s: %v", conf.RegistryAddr, err) } @@ -59,6 +60,7 @@ func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amq conf, logger, db, + cache, ebCh, consul, conf.AppName, @@ -66,14 +68,22 @@ func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amq conf.KVNamespace, } - go func(s *Server) { // Consul KV config updater - interval := time.Second * 30 + go func(s *Server) { // Consul KV updater + interval := time.Second * 15 ticker := time.NewTicker(interval) for range ticker.C { s.updateKVConfig() } }(s) + go func(s *Server) { // Server metadata cache updater + interval := time.Second * 5 + ticker := time.NewTicker(interval) + for range ticker.C { + s.cacheMetadata() + } + }(s) + SetupMiddlewares(s) SetupRoutes(s) @@ -114,31 +124,51 @@ func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) { return hdr.RequestID, nil } -func (s *Server) updateKVConfig() error { // FIXME: duplicated in cmd/worker/main.go +func (s *Server) Error400(c *fiber.Ctx, msg string) error { + return c.Status(fiber.StatusBadRequest).JSON(&def.ErrorResponse{Error: msg}) +} + +func (s *Server) Error404(c *fiber.Ctx, msg string) error { + return c.Status(fiber.StatusNotFound).JSON(&def.ErrorResponse{Error: msg}) +} + +func (s *Server) updateKVConfig() { // FIXME: duplicated in cmd/worker/main.go config, _, err := s.discovery.KV().Get(s.kvNmspc, nil) - if err != nil { - fmt.Println(err) - - return err - } - - if config == nil { - return errors.New("empty KV config data") + if err != nil || config == nil { + return } kvCnf := bytes.NewBuffer(config.Value) decoder := json.NewDecoder(kvCnf) if err := decoder.Decode(&s.conf); err != nil { - return err + return + } +} + +func (s *Server) cacheMetadata() { + ctx := context.Background() + key, address := "internal__"+s.conf.AppName+"__ips", s.conf.AppID // FIXME: key name + + pos := s.cache.LPos(ctx, key, address, redis.LPosArgs{}).Val() + if pos >= 0 { + s.cache.LRem(ctx, key, 0, address) } - return nil + s.cache.LPush(ctx, key, address).Err() +} + +func (s *Server) clearMetadataCache() { + ctx := context.Background() + key, address := "internal__"+s.conf.AppName+"__ips", s.conf.AppID // FIXME: key name + + s.cache.LRem(ctx, key, 0, address) } func (s *Server) gracefulShutdown() error { s.log.Log("Server is going down...") s.log.Log("Unregistering service: %s", s.discovery.GetID()) s.discovery.Unregister() + s.clearMetadataCache() s.ebCh.Close() s.db.Close() diff --git a/src/internal/app/service/basket.go b/src/internal/app/service/basket.go index 67d17b1..57c8e37 100644 --- a/src/internal/app/service/basket.go +++ b/src/internal/app/service/basket.go @@ -3,41 +3,48 @@ package service import ( "context" - def "git.pbiernat.dev/egommerce/basket-service/internal/app/definition" + "git.pbiernat.dev/egommerce/api-entities/model" "git.pbiernat.dev/egommerce/basket-service/internal/app/event" + "git.pbiernat.dev/egommerce/go-api-pkg/api" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" - amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" + "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" "github.com/georgysavva/scany/v2/pgxscan" + "github.com/go-redis/redis/v8" "github.com/jackc/pgx/v5/pgxpool" - base "github.com/streadway/amqp" + "github.com/streadway/amqp" +) + +const ( + SERVICE_USER_AGENT = "basket-httpclient" ) type BasketService struct { dbConn *pgxpool.Pool - ebCh *base.Channel + redis *redis.Client + ebCh *amqp.Channel log *fluentd.Logger } -func NewBasketService(dbConn *pgxpool.Pool, chn *base.Channel, log *fluentd.Logger) *BasketService { - return &BasketService{dbConn, chn, log} +func NewBasketService(dbConn *pgxpool.Pool, redis *redis.Client, chn *amqp.Channel, log *fluentd.Logger) *BasketService { + return &BasketService{dbConn, redis, chn, log} } -func (s *BasketService) Create(basketID string) (*def.BasketModel, error) { - ctx := context.Background() +func (s *BasketService) Log(format string, val ...any) { + s.log.Log(format, val...) +} +func (s *BasketService) CreateBasket(ctx context.Context, basketID string) (*model.BasketModel, error) { sql := `INSERT INTO basket.basket(id) VALUES($1)` if _, err := s.dbConn.Exec(ctx, sql, basketID); err != nil { return nil, err } - return &def.BasketModel{ID: basketID}, nil // FIXME - WTF is that xD?? + return &model.BasketModel{ID: basketID}, nil // FIXME } -func (s *BasketService) FetchFromDB(basketID string) (*def.BasketModel, error) { - ctx := context.Background() - - basket := new(def.BasketModel) - err := pgxscan.Get(ctx, s.dbConn, basket, `SELECT id, created_at, updated_at FROM basket.basket WHERE id=$1`, basketID) +func (s *BasketService) FetchFromDB(ctx context.Context, basketID string) (*model.BasketModel, error) { + basket := new(model.BasketModel) + err := pgxscan.Get(ctx, s.dbConn, basket, `SELECT id,state,created_at,updated_at FROM basket.basket WHERE id=$1 LIMIT 1`, basketID) if err != nil { return nil, err } @@ -45,12 +52,71 @@ func (s *BasketService) FetchFromDB(basketID string) (*def.BasketModel, error) { return basket, nil } -func (s *BasketService) AddProduct(productId, basketID string, qty int) error { - ctx := context.Background() - s.log.Log("Adding product#:%s into Basket#:%s", productId, basketID) +func (s *BasketService) FetchItems(ctx context.Context, basketID string) ([]*model.BasketItemModel, error) { + items := []*model.BasketItemModel{} + sql := `SELECT id,basket_id,product_id,quantity,price,created_at FROM basket.basket_item WHERE basket_id=$1` + rows, err := s.dbConn.Query(ctx, sql, basketID) + if err != nil { + // s.Log("Fetch basket items error: %v", err) + return nil, err + } - sql := `INSERT INTO basket.basket_item(basket_id, product_id) VALUES($1,$2)` - if _, err := s.dbConn.Exec(ctx, sql, basketID, productId); err != nil { + if err := pgxscan.ScanAll(&items, rows); err != nil { + // s.Log("Fetch basket items error: %v", err) + return nil, err + } + + return items, nil +} + +func (s *BasketService) FetchItem(ctx context.Context, basketID string, productID int) (*model.BasketItemModel, error) { + item := new(model.BasketItemModel) + sql := `SELECT id,basket_id,product_id,quantity,price,created_at FROM basket.basket_item WHERE basket_id=$1 AND product_id=$2 LIMIT 1` + err := pgxscan.Get(ctx, s.dbConn, item, sql, basketID, productID) + if err != nil { + return nil, err + } + + return item, nil +} + +func (s *BasketService) AddItem(ctx context.Context, itemID int, basketID string, qty int) error { + var price float64 = 0 + pricingAPI := api.NewPricingAPI(SERVICE_USER_AGENT, s.redis) + + productPrice, err := pricingAPI.GetProductPrice(itemID) + if err == nil { + price = productPrice.Price + } + + sql := `INSERT INTO basket.basket_item(basket_id,product_id,price,quantity) VALUES($1,$2,$3,$4)` + if _, err := s.dbConn.Exec(ctx, sql, basketID, itemID, price, qty); err != nil { + return err + } + + return nil +} + +func (s *BasketService) RemoveItem(ctx context.Context, itemID int, basketID string) error { + sql := `DELETE FROM basket.basket_item WHERE basket_id=$1 AND product_id=$2` + if _, err := s.dbConn.Exec(ctx, sql, basketID, itemID); err != nil { + return err + } + + return nil +} + +func (s *BasketService) UpdateItem(ctx context.Context, item *model.BasketItemModel, qty int) error { + var price float64 = 0 + pricingAPI := api.NewPricingAPI(SERVICE_USER_AGENT, s.redis) + + productPrice, err := pricingAPI.GetProductPrice(item.ProductID) + if err == nil { + price = productPrice.Price + } + + sql := `UPDATE basket.basket_item SET quantity=$1, price=$2 WHERE basket_id=$3 AND product_id=$4` + if _, err := s.dbConn.Exec(ctx, sql, qty, price, item.BasketID, item.ProductID); err != nil { return err } @@ -60,8 +126,8 @@ func (s *BasketService) AddProduct(productId, basketID string, qty int) error { func (s *BasketService) Checkout(reqID, basketID string) (string, error) { s.log.Log("Creating initial order from basket#:%s", basketID) - msg := &event.BasketCheckoutEvent{Event: event.NewEvent(reqID), BasketID: basketID} - amqp.Publish(s.ebCh, "api-events", "basket.order.basketCheckout", msg) + msg := &event.BasketCheckoutEvent{Event: event.NewEvent(reqID), BasketID: basketID} // FIXME: send more info... + rabbitmq.Publish(s.ebCh, "api-events", "basket.order.basketCheckout", msg) return basketID, nil } diff --git a/src/internal/app/ui/basket.go b/src/internal/app/ui/basket.go new file mode 100644 index 0000000..bf76ae3 --- /dev/null +++ b/src/internal/app/ui/basket.go @@ -0,0 +1,88 @@ +package ui + +import ( + "context" + + def "git.pbiernat.dev/egommerce/api-entities/http" + "git.pbiernat.dev/egommerce/api-entities/model" + "git.pbiernat.dev/egommerce/basket-service/internal/app/service" +) + +func AddProductToBasket(srv *service.BasketService, productID, qty int, basketID, reqID string) (*model.BasketModel, error) { + ctx := context.Background() + basket, err := srv.FetchFromDB(ctx, basketID) + if err != nil { + srv.Log("Basket#:%s not found. Creating new one...", basketID) + basket, err = srv.CreateBasket(ctx, basketID) + if err != nil { + ctx.Done() // FIXME + srv.Log("Creating basket error: %v", err) + return nil, err + } + } + + item, err := srv.FetchItem(ctx, basket.ID, productID) + if err != nil { + err := srv.AddItem(ctx, productID, basket.ID, qty) + ctx.Done() // FIXME + if err != nil { + srv.Log("Error adding product to basket: %v", err) + return nil, err + } + return basket, nil + } + + qty = item.Quantity + qty + err = srv.UpdateItem(ctx, item, qty) + if err != nil { + srv.Log("UpdateItem error: %v", err) + } + ctx.Done() // FIXME + + return basket, nil +} + +func RemoveProductFromBasket(srv *service.BasketService, productID, qty int, basketID, reqID string) (*model.BasketModel, error) { + ctx := context.Background() + basket, err := srv.FetchFromDB(ctx, basketID) + if err != nil { + ctx.Done() // FIXME + return nil, err + } + + item, err := srv.FetchItem(ctx, basket.ID, productID) + if err != nil { + ctx.Done() // FIXME + return nil, err + } + + if item.Quantity <= qty { + err = srv.RemoveItem(ctx, item.ProductID, item.BasketID) + if err != nil { + ctx.Done() // FIXME + return nil, err + } + } else { + qty = item.Quantity - qty + err = srv.UpdateItem(ctx, item, qty) + if err != nil { + srv.Log("UpdateItem error: %v", err) + } + } + ctx.Done() // FIXME + + return basket, nil +} + +func CheckoutBasket(srv *service.BasketService, basketID, reqID string) (*def.BasketCheckoutResponse, error) { + // ctx := context.Background() + res := &def.BasketCheckoutResponse{} + basketID, err := srv.Checkout(reqID, basketID) + if err != nil { + return res, err + } + res.ID = basketID + // ctx.Done() // FIXME + + return res, nil +} From f66662111e379369d180aec68076b820a5274667 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Mon, 20 Mar 2023 17:33:14 +0100 Subject: [PATCH 15/17] update --- .env.dist | 14 +++++++++++++- src/cmd/worker/main.go | 26 +++++++++++--------------- src/go.sum | 2 -- src/internal/app/server/config.go | 7 ++++--- src/internal/app/server/server.go | 22 ++++++++++++---------- src/internal/app/service/basket.go | 6 ++++++ 6 files changed, 46 insertions(+), 31 deletions(-) diff --git a/.env.dist b/.env.dist index 84c5d45..03b6ce0 100644 --- a/.env.dist +++ b/.env.dist @@ -1,4 +1,16 @@ SERVER_ADDR=:80 + +APP_NAME=basket-svc +APP_DOMAIN=basket-svc +APP_PATH_PREFIX=/basket +APP_KV_NAMESPACE=dev.egommerce/service/basket-svc + +LOGGER_ADDR=api-logger:24224 +REGISTRY_ADDR=api-registry:8500 DATABASE_URL=postgres://postgres:12345678@postgres-db:5432/egommerce +CACHE_ADDR=api-cache:6379 +CACHE_PASSWORD=12345678 MONGODB_URL=mongodb://mongodb:12345678@mongo-db:27017 -EVENTBUS_URL=amqp://guest:guest@api-eventbus:5672 \ No newline at end of file +EVENTBUS_URL=amqp://guest:guest@api-eventbus:5672 + + diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go index 6bc2717..e9d9fd3 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -67,8 +67,7 @@ func main() { } go func(consul *discovery.Service) { - interval := time.Second * 3 - ticker := time.NewTicker(interval) + ticker := time.NewTicker(time.Second * 15) for range ticker.C { updateKVConfig(consul, c) // FIXME: duplicated in internal/app/server/server.go } @@ -76,7 +75,7 @@ func main() { // db conn dbConn, err := database.Connect(c.DbURL) - if err != nil { // fixme: add wait-for-db... + if err != nil { logger.Log("Failed to connect to Database server: %v\n", err) os.Exit(1) } @@ -174,26 +173,23 @@ func main() { qty := int(data["quantity"].(float64)) basket, err := ui.AddProductToBasket(basketSrv, productID, qty, basketID, reqID) - if err != nil { - fmt.Println("worker error: ", err) - logger.Log("%s error: %s", event.EVENT_PRODUCT_ADDED_TO_BASKET, err.Error()) - d.Reject(false) // FIXME: or Nack? how to handle erros in queue... - break + if err == nil { + logger.Log("Product #%s added to basket #%s. ReqID: #%s", productID, basket.ID, reqID) } - - logger.Log("Product #%s added to basket #%s. ReqID: #%s", productID, basket.ID, reqID) case strings.Contains(eName, event.EVENT_PRODUCT_REMOVED_FROM_BASKET): productID := int(data["product_id"].(float64)) qty := int(data["quantity"].(float64)) basket, err := ui.RemoveProductFromBasket(basketSrv, productID, qty, basketID, reqID) - if err != nil { - logger.Log("%s error: %s", event.EVENT_PRODUCT_ADDED_TO_BASKET, err.Error()) - d.Reject(false) // FIXME: or Nack? how to handle erros in queue... - break + if err == nil { + logger.Log("Product #%s removed from basket #%s. ReqID: #%s", productID, basket.ID, reqID) } + } - logger.Log("Product #%s removed from basket #%s. ReqID: #%s", productID, basket.ID, reqID) + if err != nil { + logger.Log("%s error: %s", eName, err.Error()) + d.Reject(false) // FIXME: or Nack? how to handle erros in queue... + return } logger.Log("ACK: %s", eName) diff --git a/src/go.sum b/src/go.sum index 505f01a..af6828c 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,8 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= git.pbiernat.dev/egommerce/api-entities v0.0.26 h1:Avz02GINwuYWOjw1fmZIJ3QgGEIz3a5vRQZNaxxUQIk= git.pbiernat.dev/egommerce/api-entities v0.0.26/go.mod h1:+BXvUcr6Cr6QNpJsW8BUfe1vVILdWDADNE0e3u0lNvU= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.135 h1:qOa6MB6d2/lr0t9c3WWP84rf/T57PNYgizTmuNCDws8= -git.pbiernat.dev/egommerce/go-api-pkg v0.0.135/go.mod h1:w2N79aoumjrrcrGPJLkCwxAHtrLd7G4Uj8VOxvPooa0= git.pbiernat.dev/egommerce/go-api-pkg v0.0.136 h1:SzJRAkqJKdng/3d0V7o/R0yGh7QaZynPBn/P++on9RA= git.pbiernat.dev/egommerce/go-api-pkg v0.0.136/go.mod h1:w2N79aoumjrrcrGPJLkCwxAHtrLd7G4Uj8VOxvPooa0= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= diff --git a/src/internal/app/server/config.go b/src/internal/app/server/config.go index 5213283..1940c7b 100644 --- a/src/internal/app/server/config.go +++ b/src/internal/app/server/config.go @@ -20,9 +20,10 @@ type Config struct { EventBusURL string `json:"eventbus_url"` EventBusExchange string `json:"eventbus_exchange"` EventBusQueue string `json:"eventbus_queue"` - HttpReadTimeout int `json:"http_read_timeout"` - HttpWriteTimeout int `json:"http_write_timeout"` - HttpIdleTimeout int `json:"http_idle_timeout"` + + HttpReadTimeout int `json:"http_read_timeout"` + HttpWriteTimeout int `json:"http_write_timeout"` + HttpIdleTimeout int `json:"http_idle_timeout"` // Fields with json mapping are available trough ConsulKV } diff --git a/src/internal/app/server/server.go b/src/internal/app/server/server.go index ef406e9..9fac46c 100644 --- a/src/internal/app/server/server.go +++ b/src/internal/app/server/server.go @@ -77,8 +77,7 @@ func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, cache *re }(s) go func(s *Server) { // Server metadata cache updater - interval := time.Second * 5 - ticker := time.NewTicker(interval) + ticker := time.NewTicker(time.Second * 5) for range ticker.C { s.cacheMetadata() } @@ -90,10 +89,10 @@ func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, cache *re return s } -func (s *Server) Start() { - err := s.Listen(s.addr) - s.log.Log("Starting error: %v", err) -} +// func (s *Server) Start() { +// err := s.Listen(s.addr) +// s.log.Log("Starting error: %v", err) +// } func (s *Server) StartWithGracefulShutdown(forever chan struct{}) { go func() { @@ -147,7 +146,7 @@ func (s *Server) updateKVConfig() { // FIXME: duplicated in cmd/worker/main.go func (s *Server) cacheMetadata() { ctx := context.Background() - key, address := "internal__"+s.conf.AppName+"__ips", s.conf.AppID // FIXME: key name + key, address := s.getMetadataIPsKey(), s.conf.AppID pos := s.cache.LPos(ctx, key, address, redis.LPosArgs{}).Val() if pos >= 0 { @@ -159,14 +158,17 @@ func (s *Server) cacheMetadata() { func (s *Server) clearMetadataCache() { ctx := context.Background() - key, address := "internal__"+s.conf.AppName+"__ips", s.conf.AppID // FIXME: key name + key, address := s.getMetadataIPsKey(), s.conf.AppID s.cache.LRem(ctx, key, 0, address) } +func (s *Server) getMetadataIPsKey() string { + return "internal__" + s.conf.AppName + "__ips" +} + func (s *Server) gracefulShutdown() error { - s.log.Log("Server is going down...") - s.log.Log("Unregistering service: %s", s.discovery.GetID()) + s.log.Log("Server is going down... Unregistering service: %s", s.discovery.GetID()) s.discovery.Unregister() s.clearMetadataCache() diff --git a/src/internal/app/service/basket.go b/src/internal/app/service/basket.go index 57c8e37..4c26160 100644 --- a/src/internal/app/service/basket.go +++ b/src/internal/app/service/basket.go @@ -94,6 +94,8 @@ func (s *BasketService) AddItem(ctx context.Context, itemID int, basketID string return err } + // update basket updated_at field... + return nil } @@ -103,6 +105,8 @@ func (s *BasketService) RemoveItem(ctx context.Context, itemID int, basketID str return err } + // update basket updated_at field... + return nil } @@ -120,6 +124,8 @@ func (s *BasketService) UpdateItem(ctx context.Context, item *model.BasketItemMo return err } + // update basket updated_at field... + return nil } From b6caa335b15a08c25cbe981fb17f8fd67cf82518 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Thu, 30 Mar 2023 22:17:09 +0200 Subject: [PATCH 16/17] Added LICENSE --- LICENSE.md | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..d0e1a69 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,173 @@ +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International + +Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. + +**Using Creative Commons Public Licenses** + +Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. + +* __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors). + +* __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees). + +## Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +### Section 1 – Definitions. + +a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. __BY-NC-SA Compatible License__ means a license listed at [creativecommons.org/compatiblelicenses](http://creativecommons.org/compatiblelicenses), approved by Creative Commons as essentially the equivalent of this Public License. + +d. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. __License Elements__ means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution, NonCommercial, and ShareAlike. + +h. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +i. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +j. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License. + +k. __NonCommercial__ means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +l. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +m. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +n. __You__ means the individual or entity exercising the Licensed Rights under this Public License. __Your__ has a corresponding meaning. + +### Section 2 – Scope. + +a. ___License grant.___ + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. __Term.__ The term of this Public License is specified in Section 6(a). + + 4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. __Downstream recipients.__ + + A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + B. __Additional offer from the Licensor – Adapted Material.__ Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply. + + C. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. ___Other rights.___ + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +### Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. ___Attribution.___ + + 1. If You Share the Licensed Material (including in modified form), You must: + + A. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ___ShareAlike.___ + +In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + +1. The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC-SA Compatible License. + +2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + +3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +### Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. + +### Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__ + +b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__ + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +### Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +### Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +### Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. + +> Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. +> +> Creative Commons may be contacted at creativecommons.org From 751e1c70e6a730f89010ac398e4013bb76f62564 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Tue, 4 Apr 2023 00:57:11 +0200 Subject: [PATCH 17/17] Refactoring - added Functional Option pattern --- src/cmd/migrate/main.go | 33 +- src/cmd/server/main.go | 146 ++++---- src/cmd/worker/main.go | 75 ++-- src/go.mod | 2 +- src/go.sum | 4 + src/internal/app/log.go | 20 -- src/internal/app/server/basket_handler.go | 31 +- src/internal/app/server/config.go | 32 -- src/internal/app/server/health_handler.go | 11 +- src/internal/app/server/middleware.go | 33 ++ src/internal/app/server/router.go | 35 +- src/internal/app/server/server.go | 319 +++++++++++------- src/internal/app/service/basket.go | 6 +- src/internal/common/config.go | 84 +++++ .../config/env.go => pkg/config/config.go} | 2 +- src/{internal/app => pkg}/database/connect.go | 0 src/pkg/server/config.go | 21 ++ src/pkg/server/server.go | 101 ++++++ 18 files changed, 599 insertions(+), 356 deletions(-) delete mode 100644 src/internal/app/log.go delete mode 100644 src/internal/app/server/config.go create mode 100644 src/internal/app/server/middleware.go create mode 100644 src/internal/common/config.go rename src/{internal/app/config/env.go => pkg/config/config.go} (72%) rename src/{internal/app => pkg}/database/connect.go (100%) create mode 100644 src/pkg/server/config.go create mode 100644 src/pkg/server/server.go diff --git a/src/cmd/migrate/main.go b/src/cmd/migrate/main.go index fecaf60..8894ff7 100644 --- a/src/cmd/migrate/main.go +++ b/src/cmd/migrate/main.go @@ -6,10 +6,13 @@ import ( "log" "os" - "git.pbiernat.dev/egommerce/basket-service/internal/app/config" - "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" "github.com/go-pg/migrations/v8" "github.com/go-pg/pg/v10" + + "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" + + "git.pbiernat.dev/egommerce/basket-service/internal/common" + cnf "git.pbiernat.dev/egommerce/basket-service/pkg/config" ) const ( @@ -32,16 +35,24 @@ Usage: ` func main() { - if config.ErrLoadingEnvs != nil { - log.Panicln("Error loading .env file", config.ErrLoadingEnvs) + if cnf.ErrLoadingEnvs != nil { + log.Panicln("Error loading .env file", cnf.ErrLoadingEnvs) } - // dbURL := config.GetEnv("DATABASE_URL", defDbURL) - loggerAddr := config.GetEnv("LOGGER_ADDR", defLoggerAddr) - mTblName := config.GetEnv("MIGRATIONS_TABLE_NAME", defMigrationsTableName) + c := common.NewConfig() - logHost, logPort := fluentd.ParseAddr(loggerAddr) - logger := fluentd.NewLogger(defAppName, logHost, logPort) + // dbURL := cnf.GetEnv("DATABASE_URL", defDbURL) + mTblName := cnf.GetEnv("MIGRATIONS_TABLE_NAME", defMigrationsTableName) + + logHost, logPort, err := fluentd.ParseAddr(c.LoggerAddr) + if err != nil { + log.Fatalf("Error parsing logger addr: %s. Err: %v", c.LoggerAddr, err) + } + + logger, err := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) // @Refactor NewLogger return (logger, error) + if err != nil { + log.Fatalf("Error connecting to %s:%d. Err: %v", logHost, logPort, err) + } defer logger.Close() flag.Usage = usage @@ -56,8 +67,8 @@ func main() { mig := migrations.NewCollection() mig.SetTableName(mTblName) - err := mig.DiscoverSQLMigrations("./migrations") - if err != nil { + + if err := mig.DiscoverSQLMigrations("./migrations"); err != nil { logger.Log("migration dicovery error: %#v", err) } diff --git a/src/cmd/server/main.go b/src/cmd/server/main.go index 83d60ff..c078125 100644 --- a/src/cmd/server/main.go +++ b/src/cmd/server/main.go @@ -1,97 +1,83 @@ package main import ( + "fmt" "log" "os" - "strconv" - "git.pbiernat.dev/egommerce/basket-service/internal/app/config" - "git.pbiernat.dev/egommerce/basket-service/internal/app/database" + cnf "git.pbiernat.dev/egommerce/basket-service/pkg/config" + "git.pbiernat.dev/egommerce/basket-service/internal/app/server" - "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" - amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" - "github.com/go-redis/redis/v8" -) - -const ( - defAppName = "basket-svc" - defAppDomain = "basket-svc" - defPathPrefix = "/basket" - defNetAddr = ":80" - defLoggerAddr = "api-logger:24224" - defRegistryAddr = "api-registry:8500" - defDbURL = "postgres://postgres:12345678@postgres-db:5432/egommerce" - defCacheAddr = "api-cache:6379" - defCachePassword = "12345678" - defMongoDbURL = "mongodb://mongodb:12345678@mongo-db:27017" - defEventBusURL = "amqp://guest:guest@api-eventbus:5672" - ebEventsExchange = "api-events" - ebEventsQueue = "basket-svc" - defKVNmspc = "dev.egommerce/service/basket-svc" + "git.pbiernat.dev/egommerce/basket-service/internal/common" ) func main() { - if config.ErrLoadingEnvs != nil { - log.Panicln("Error loading .env file", config.ErrLoadingEnvs) + if cnf.ErrLoadingEnvs != nil { + log.Panicln("Error loading .env file", cnf.ErrLoadingEnvs) } - c := new(server.Config) - c.AppID, _ = os.Hostname() - c.AppName = config.GetEnv("APP_NAME", defAppName) - c.AppDomain = config.GetEnv("APP_DOMAIN", defAppDomain) - c.PathPrefix = config.GetEnv("APP_PATH_PREFIX", defPathPrefix) - c.NetAddr = config.GetEnv("SERVER_ADDR", defNetAddr) - c.Port, _ = strconv.Atoi(c.NetAddr[1:]) - c.LoggerAddr = config.GetEnv("LOGGER_ADDR", defLoggerAddr) - c.RegistryAddr = config.GetEnv("REGISTRY_ADDR", defRegistryAddr) - c.DbURL = config.GetEnv("DATABASE_URL", defDbURL) - c.CacheAddr = config.GetEnv("CACHE_ADDR", defCacheAddr) - c.CachePassword = config.GetEnv("CACHE_PASSWORD", defCachePassword) - c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) - c.EventBusExchange = ebEventsExchange - c.KVNamespace = config.GetEnv("APP_KV_NAMESPACE", defKVNmspc) - - logHost, logPort := fluentd.ParseAddr(c.LoggerAddr) - logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) - defer logger.Close() - - // db conn - dbConn, err := database.Connect(c.DbURL) - if err != nil { // fixme: add wait-for-db... - logger.Log("Failed to connect to Database server: %v\n", err) - os.Exit(1) - } - defer dbConn.Close() - - // redis conn - redis := redis.NewClient(&redis.Options{ - Addr: c.CacheAddr, - Password: c.CachePassword, - DB: 0, - }) - defer redis.Close() - - // eventbus conn - ebConn, ebCh, err := amqp.Open(c.EventBusURL) - if err != nil { - logger.Log("Failed to connect to EventBus server: %v\n", err) - os.Exit(1) - } - defer ebCh.Close() - defer amqp.Close(ebConn) - - err = amqp.NewExchange(ebCh, c.EventBusExchange) - if err != nil { - logger.Log("Failed to declare EventBus exchange: %v\n", err) - os.Exit(1) - } - - // start server - srv := server.NewServer(c, logger, dbConn, redis, ebCh) + c := common.NewConfig() + srv := server.New( + c, + server.WithCache(c), + server.WithDatabase(c), + server.WithEventbus(c), + server.WithLogger(c), + server.WithRegistry(c), + ) forever := make(chan struct{}) - srv.StartWithGracefulShutdown(forever) + + err := srv.Base.Start(forever, srv.Shutdown()) + // server.SetupMiddleware(srv) + // server.SetupRouter(srv) + <-forever - // os.Exit(1) + if err != nil { + log.Fatalf("Failed to start server. Reason: %v\n", err) + os.Exit(1) + } + + fmt.Println("Done.") + os.Exit(0) + + // c.AppDomain = cnf.GetEnv("APP_DOMAIN", defAppDomain) + // c.Port, _ = strconv.Atoi(c.NetAddr[1:]) + // c.KVNamespace = cnf.GetEnv("APP_KV_NAMESPACE", defKVNmspc) + + // logHost, logPort := fluentd.ParseAddr(c.LoggerAddr) + // logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) + // defer logger.Close() + + // db conn + // dbConn, err := database.Connect(c.DbURL) + // if err != nil { // fixme: add wait-for-db... + // logger.Log("Failed to connect to Database server: %v\n", err) + // os.Exit(1) + // } + // defer dbConn.Close() + + // redis conn + // redis := redis.NewClient(&redis.Options{ + // Addr: c.CacheAddr, + // Password: c.CachePassword, + // DB: 0, + // }) + // defer redis.Close() + + // eventbus conn + // ebConn, ebCh, err := amqp.Open(c.EventBusURL) + // if err != nil { + // logger.Log("Failed to connect to EventBus server: %v\n", err) + // os.Exit(1) + // } + // defer ebCh.Close() + // defer amqp.Close(ebConn) + + // err = amqp.NewExchange(ebCh, c.EventBusExchange) + // if err != nil { + // logger.Log("Failed to declare EventBus exchange: %v\n", err) + // os.Exit(1) + // } } diff --git a/src/cmd/worker/main.go b/src/cmd/worker/main.go index e9d9fd3..8924267 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -1,9 +1,6 @@ package main import ( - "bytes" - "encoding/json" - "errors" "fmt" "log" "os" @@ -12,17 +9,19 @@ import ( "syscall" "time" - "git.pbiernat.dev/egommerce/basket-service/internal/app/config" - "git.pbiernat.dev/egommerce/basket-service/internal/app/database" - "git.pbiernat.dev/egommerce/basket-service/internal/app/event" - "git.pbiernat.dev/egommerce/basket-service/internal/app/server" - "git.pbiernat.dev/egommerce/basket-service/internal/app/service" - "git.pbiernat.dev/egommerce/basket-service/internal/app/ui" - discovery "git.pbiernat.dev/egommerce/go-api-pkg/consul" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" "github.com/go-redis/redis/v8" "github.com/streadway/amqp" + + "git.pbiernat.dev/egommerce/go-api-pkg/consul" + + "git.pbiernat.dev/egommerce/basket-service/internal/app/event" + "git.pbiernat.dev/egommerce/basket-service/internal/app/service" + "git.pbiernat.dev/egommerce/basket-service/internal/app/ui" + "git.pbiernat.dev/egommerce/basket-service/internal/common" + "git.pbiernat.dev/egommerce/basket-service/pkg/config" + "git.pbiernat.dev/egommerce/basket-service/pkg/database" ) const ( @@ -44,34 +43,30 @@ func main() { log.Panicln("Error loading .env file", config.ErrLoadingEnvs) } - c := new(server.Config) - c.AppID, _ = os.Hostname() - c.AppName = config.GetEnv("APP_NAME", defAppName) - c.LoggerAddr = config.GetEnv("LOGGER_ADDR", defLoggerAddr) - c.RegistryAddr = config.GetEnv("REGISTRY_ADDR", defRegistryAddr) - c.DbURL = config.GetEnv("DATABASE_URL", defDbURL) - c.CacheAddr = config.GetEnv("CACHE_ADDR", defCacheAddr) - c.CachePassword = config.GetEnv("CACHE_PASSWORD", defCachePassword) - c.EventBusURL = config.GetEnv("EVENTBUS_URL", defEventBusURL) - c.EventBusExchange = ebEventsExchange - c.EventBusQueue = ebEventsQueue - c.KVNamespace = config.GetEnv("APP_KV_NAMESPACE", defKVNmspc) + c := common.NewConfig() + logHost, logPort, err := fluentd.ParseAddr(c.LoggerAddr) + if err != nil { + log.Fatalf("Error parsing logger addr: %s. Err: %v", c.LoggerAddr, err) + } - logHost, logPort := fluentd.ParseAddr(c.LoggerAddr) - logger := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) + logger, err := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) // @Refactor NewLogger return (logger, error) + if err != nil { + log.Fatalf("Error connecting to %s:%d. Err: %v", logHost, logPort, err) + } defer logger.Close() - consul, err := discovery.NewService(c.RegistryAddr, c.AppID, c.AppName, c.AppID, "", "", 0) + // consul, err := consul.NewService(c.RegistryAddr, c.Base.AppID, c.Base.AppName, c.Base.AppID, "", "", 0) + registry, err := consul.NewService(c.RegistryAddr, c.Base.AppID, c.Base.AppName, c.Base.AppID, "", "", 0) if err != nil { logger.Log("Error connecting to %s: %v", c.RegistryAddr, err) } - go func(consul *discovery.Service) { + go func(consul *consul.Service) { ticker := time.NewTicker(time.Second * 15) for range ticker.C { updateKVConfig(consul, c) // FIXME: duplicated in internal/app/server/server.go } - }(consul) + }(registry) // db conn dbConn, err := database.Connect(c.DbURL) @@ -202,21 +197,21 @@ func main() { <-forever } -func updateKVConfig(s *discovery.Service, oldCnf *server.Config) error { // FIXME: duplicated in internal/app/server/server.go - data, _, err := s.KV().Get(oldCnf.KVNamespace, nil) - if err != nil { - return err - } +func updateKVConfig(s *consul.Service, oldCnf *common.Config) error { // FIXME: duplicated in internal/app/server/server.go + // data, _, err := s.KV().Get(oldCnf.KVNamespace, nil) + // if err != nil { + // return err + // } - if data == nil { - return errors.New("empty KV config data") - } + // if data == nil { + // return errors.New("empty KV config data") + // } - buf := bytes.NewBuffer(data.Value) - decoder := json.NewDecoder(buf) - if err := decoder.Decode(oldCnf); err != nil { - return err - } + // buf := bytes.NewBuffer(data.Value) + // decoder := json.NewDecoder(buf) + // if err := decoder.Decode(oldCnf); err != nil { + // return err + // } return nil } diff --git a/src/go.mod b/src/go.mod index 4bb84ca..ee0ac61 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( git.pbiernat.dev/egommerce/api-entities v0.0.26 - git.pbiernat.dev/egommerce/go-api-pkg v0.0.136 + git.pbiernat.dev/egommerce/go-api-pkg v0.0.150 github.com/georgysavva/scany/v2 v2.0.0 github.com/go-pg/migrations/v8 v8.1.0 github.com/go-pg/pg/v10 v10.10.7 diff --git a/src/go.sum b/src/go.sum index af6828c..a0201ad 100644 --- a/src/go.sum +++ b/src/go.sum @@ -3,6 +3,10 @@ git.pbiernat.dev/egommerce/api-entities v0.0.26 h1:Avz02GINwuYWOjw1fmZIJ3QgGEIz3 git.pbiernat.dev/egommerce/api-entities v0.0.26/go.mod h1:+BXvUcr6Cr6QNpJsW8BUfe1vVILdWDADNE0e3u0lNvU= git.pbiernat.dev/egommerce/go-api-pkg v0.0.136 h1:SzJRAkqJKdng/3d0V7o/R0yGh7QaZynPBn/P++on9RA= git.pbiernat.dev/egommerce/go-api-pkg v0.0.136/go.mod h1:w2N79aoumjrrcrGPJLkCwxAHtrLd7G4Uj8VOxvPooa0= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.149 h1:7K4z/XUMAPrnvOPcFfkeeNCpuc5IHoC1Pd68Ht7q9Ts= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.149/go.mod h1:w2N79aoumjrrcrGPJLkCwxAHtrLd7G4Uj8VOxvPooa0= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.150 h1:DMM3Kxb6HNw4BExA7Ss7P9ivs+TIeO9DxjfHPKeWrSg= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.150/go.mod h1:w2N79aoumjrrcrGPJLkCwxAHtrLd7G4Uj8VOxvPooa0= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= diff --git a/src/internal/app/log.go b/src/internal/app/log.go deleted file mode 100644 index 1728b1a..0000000 --- a/src/internal/app/log.go +++ /dev/null @@ -1,20 +0,0 @@ -package app - -import ( - "log" -) - -const AppName = "basket-svc" - -func Panic(v ...any) { - log.Panicln(AppName+":", v) -} - -func Panicf(format string, v ...any) { - log.Panicf(AppName+": "+format, v...) -} - -func Panicln(v ...any) { - v = append([]any{AppName + ":"}, v...) - log.Panicln(v...) -} diff --git a/src/internal/app/server/basket_handler.go b/src/internal/app/server/basket_handler.go index f4f3e6a..10905df 100644 --- a/src/internal/app/server/basket_handler.go +++ b/src/internal/app/server/basket_handler.go @@ -1,30 +1,31 @@ package server +// REFACTOR: APP DEDICATED CODE import ( "context" "time" - def "git.pbiernat.dev/egommerce/api-entities/http" + "git.pbiernat.dev/egommerce/api-entities/http" "git.pbiernat.dev/egommerce/basket-service/internal/app/service" "git.pbiernat.dev/egommerce/basket-service/internal/app/ui" "github.com/gofiber/fiber/v2" ) func (s *Server) GetBasketHandler(c *fiber.Ctx) error { - req := new(def.GetBasketRequest) + req := new(http.GetBasketRequest) if err := c.BodyParser(req); err != nil { - return s.Error400(c, err.Error()) + return s.Base.Error400(c, err.Error()) } basketID := req.BasketID - basketSrv := service.NewBasketService(s.db, s.cache, s.ebCh, s.log) + basketSrv := service.NewBasketService(s.Database, s.Cache, s.Eventbus, s.Logger) ctx := context.Background() basket, err := basketSrv.FetchFromDB(ctx, basketID) if err != nil { - return s.Error400(c, "Failed to retrieve basket") + return s.Base.Error400(c, "Failed to retrieve basket") } - res := &def.GetBasketResponse{ + res := &http.GetBasketResponse{ ID: basket.ID, State: basket.State, CreatedAt: time.Duration(basket.CreatedAt.Time.Unix()), @@ -38,16 +39,16 @@ func (s *Server) GetBasketHandler(c *fiber.Ctx) error { func (s *Server) GetBasketItemsHandler(c *fiber.Ctx) error { basketID := c.Params("basketId", "") - basketSrv := service.NewBasketService(s.db, s.cache, s.ebCh, s.log) + basketSrv := service.NewBasketService(s.Database, s.Cache, s.Eventbus, s.Logger) ctx := context.Background() items, err := basketSrv.FetchItems(ctx, basketID) if err != nil { - return s.Error400(c, "Failed to retrieve basket items") + return s.Base.Error400(c, "Failed to retrieve basket items") } - var res []*def.GetBasketItemsResponse // FIXME + var res []*http.GetBasketItemsResponse for _, item := range items { - resItem := &def.GetBasketItemsResponse{ + resItem := &http.GetBasketItemsResponse{ ID: item.ID, BasketID: item.BasketID, ProductID: item.ProductID, @@ -65,17 +66,17 @@ func (s *Server) GetBasketItemsHandler(c *fiber.Ctx) error { } func (s *Server) CheckoutHandler(c *fiber.Ctx) error { - reqID, _ := s.GetRequestID(c) - req := new(def.BasketCheckoutRequest) + reqID, _ := s.Base.GetRequestID(c) + req := new(http.BasketCheckoutRequest) if err := c.BodyParser(req); err != nil { - return s.Error400(c, err.Error()) + return s.Base.Error400(c, err.Error()) } basketID := req.BasketID - basketSrv := service.NewBasketService(s.db, s.cache, s.ebCh, s.log) + basketSrv := service.NewBasketService(s.Database, s.Cache, s.Eventbus, s.Logger) res, err := ui.CheckoutBasket(basketSrv, basketID, reqID) if err != nil { - return s.Error400(c, "Failed to create order") + return s.Base.Error400(c, "Failed to create order") } return c.JSON(res) diff --git a/src/internal/app/server/config.go b/src/internal/app/server/config.go deleted file mode 100644 index 1940c7b..0000000 --- a/src/internal/app/server/config.go +++ /dev/null @@ -1,32 +0,0 @@ -package server - -import "fmt" - -type Config struct { - AppID string - AppName string - AppDomain string - PathPrefix string - NetAddr string - Port int - RegistryAddr string - KVNamespace string - - LoggerAddr string `json:"logger_addr"` - DbURL string `json:"db_url"` - CacheAddr string `json:"cache_addr"` - CachePassword string `json:"cache_password"` - MongoDbUrl string `json:"mongodb_url"` - EventBusURL string `json:"eventbus_url"` - EventBusExchange string `json:"eventbus_exchange"` - EventBusQueue string `json:"eventbus_queue"` - - HttpReadTimeout int `json:"http_read_timeout"` - HttpWriteTimeout int `json:"http_write_timeout"` - HttpIdleTimeout int `json:"http_idle_timeout"` - // Fields with json mapping are available trough ConsulKV -} - -func (c *Config) GetAppFullName() string { - return fmt.Sprintf("%s_%s", c.AppName, c.AppID) -} diff --git a/src/internal/app/server/health_handler.go b/src/internal/app/server/health_handler.go index 73d756e..8c0a64e 100644 --- a/src/internal/app/server/health_handler.go +++ b/src/internal/app/server/health_handler.go @@ -1,17 +1,18 @@ package server +// REFACTOR: UNIVERSAL SERVER CODE import ( "github.com/gofiber/fiber/v2" - def "git.pbiernat.dev/egommerce/api-entities/http" + "git.pbiernat.dev/egommerce/api-entities/http" ) -func (s *Server) HealthHandler(c *fiber.Ctx) error { - return c.JSON(&def.HealthResponse{ - Status: "OK", +func (s *Server) HealthHandler(c *fiber.Ctx) error { // TODO add necessary logic + return c.JSON(&http.HealthResponse{ + Status: "OKa", }) } func (s *Server) ConfigHandler(c *fiber.Ctx) error { - return c.JSON(s.conf) + return c.JSON(s.Config) } diff --git a/src/internal/app/server/middleware.go b/src/internal/app/server/middleware.go new file mode 100644 index 0000000..74e2cda --- /dev/null +++ b/src/internal/app/server/middleware.go @@ -0,0 +1,33 @@ +package server + +import ( + "strings" + + "github.com/gofiber/fiber/v2" + + "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" +) + +// "github.com/gofiber/fiber/v2" +// "github.com/gofiber/fiber/v2/middleware/cors" + +func SetupMiddleware(s *Server) { + s.Base.Use(defaultCORS) + s.Base.Use(LoggingMiddleware(s.Logger)) +} + +func LoggingMiddleware(log *fluentd.Logger) func(c *fiber.Ctx) error { + return func(c *fiber.Ctx) error { + path := string(c.Request().URI().Path()) + if strings.Contains(path, "/health") { + return c.Next() + } + + log.Log("Request: %s, remote: %s, via: %s", + c.Request().URI().String(), + c.Context().RemoteIP().String(), + string(c.Context().UserAgent())) + + return c.Next() + } +} diff --git a/src/internal/app/server/router.go b/src/internal/app/server/router.go index 38cb6aa..df12031 100644 --- a/src/internal/app/server/router.go +++ b/src/internal/app/server/router.go @@ -1,10 +1,9 @@ package server +// REFACTOR: APP DEDICATED CODE import ( "net/http" - "strings" - "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" ) @@ -18,24 +17,19 @@ var ( }) ) -func SetupRoutes(s *Server) { - s.App.Options("*", defaultCORS) +func SetupRouter(s *Server) { + s.Base.Options("*", defaultCORS) - s.App.Get("/health", s.HealthHandler) - s.App.Get("/config", s.ConfigHandler) + s.Base.Get("/health", s.HealthHandler) + s.Base.Get("/config", s.ConfigHandler) - api := s.App.Group("/api") + api := s.Base.Group("/api") v1 := api.Group("/v1") v1.Get("/basket", s.GetBasketHandler) v1.Get("/basket/:basketId/items", s.GetBasketItemsHandler) v1.Post("/checkout", s.CheckoutHandler) } -func SetupMiddlewares(s *Server) { - s.App.Use(defaultCORS) - s.App.Use(LoggingMiddleware(s.log)) -} - func CORSPreflightMiddleware(c *fiber.Ctx) error { if string(c.Request().Header.Method()) == http.MethodOptions { c.Response().SetStatusCode(http.StatusOK) @@ -44,20 +38,3 @@ func CORSPreflightMiddleware(c *fiber.Ctx) error { return c.Next() } - -// Middlewares -func LoggingMiddleware(log *fluentd.Logger) func(c *fiber.Ctx) error { - return func(c *fiber.Ctx) error { - path := string(c.Request().URI().Path()) - if strings.Contains(path, "/health") { - return c.Next() - } - - log.Log("Request: %s, remote: %s, via: %s", - c.Request().URI().String(), - c.Context().RemoteIP().String(), - string(c.Context().UserAgent())) - - return c.Next() - } -} diff --git a/src/internal/app/server/server.go b/src/internal/app/server/server.go index 9fac46c..a7aa3c2 100644 --- a/src/internal/app/server/server.go +++ b/src/internal/app/server/server.go @@ -4,177 +4,258 @@ import ( "bytes" "context" "encoding/json" + "fmt" + "log" "os" - "os/signal" - "syscall" + "strconv" "time" "github.com/go-redis/redis/v8" - "github.com/gofiber/fiber/v2" "github.com/jackc/pgx/v5/pgxpool" "github.com/streadway/amqp" - def "git.pbiernat.dev/egommerce/api-entities/http" - discovery "git.pbiernat.dev/egommerce/go-api-pkg/consul" + "git.pbiernat.dev/egommerce/go-api-pkg/consul" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" + + db "git.pbiernat.dev/egommerce/basket-service/pkg/database" + srv "git.pbiernat.dev/egommerce/basket-service/pkg/server" + + "git.pbiernat.dev/egommerce/basket-service/internal/common" ) -type Server struct { - *fiber.App - conf *Config - log *fluentd.Logger - db *pgxpool.Pool - cache *redis.Client - ebCh *amqp.Channel - discovery *discovery.Service - name string - addr string - kvNmspc string -} +type ( + Server struct { + Base *srv.Server + Config *common.Config -type Headers struct { - RequestID string `reqHeader:"x-request-id"` -} + Cache *redis.Client + Database *pgxpool.Pool + Eventbus *amqp.Channel + Logger *fluentd.Logger + Registry *consul.Service -func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, cache *redis.Client, ebCh *amqp.Channel) *Server { - consul, err := discovery.NewService(conf.RegistryAddr, conf.AppID, conf.AppName, conf.AppID, conf.AppDomain, conf.PathPrefix, conf.Port) - if err != nil { - logger.Log("Error connecting to %s: %v", conf.RegistryAddr, err) + kvNmspc string } - logger.Log("Registering service with name: %s, address: %s", consul.Name, consul.Address) - err = consul.Register() - if err != nil { - logger.Log("register error: %v", err) + OptionFn func(*Server) error +) + +func New(c *common.Config, opts ...OptionFn) *Server { + svr := &Server{ + Base: srv.New(c.Base), } - cnf := fiber.Config{ - AppName: conf.AppName, - ServerHeader: conf.AppName, - ReadTimeout: time.Millisecond * 50, - WriteTimeout: time.Millisecond * 50, - IdleTimeout: time.Millisecond * 50, - } - s := &Server{ - fiber.New(cnf), - conf, - logger, - db, - cache, - ebCh, - consul, - conf.AppName, - conf.NetAddr, - conf.KVNamespace, - } - - go func(s *Server) { // Consul KV updater - interval := time.Second * 15 - ticker := time.NewTicker(interval) - for range ticker.C { - s.updateKVConfig() + for _, opt := range opts { + if err := opt(svr); err != nil { + log.Fatalf("Failed to start HTTP Server. Err: %v\n", err) } - }(s) + } - go func(s *Server) { // Server metadata cache updater - ticker := time.NewTicker(time.Second * 5) - for range ticker.C { - s.cacheMetadata() - } - }(s) + SetupMiddleware(svr) + SetupRouter(svr) - SetupMiddlewares(s) - SetupRoutes(s) - - return s + return svr } -// func (s *Server) Start() { -// err := s.Listen(s.addr) -// s.log.Log("Starting error: %v", err) +func WithCache(c *common.Config) OptionFn { + redis := redis.NewClient(&redis.Options{ + Addr: c.CacheAddr, + Password: c.CachePassword, + DB: 0, + }) + + return func(s *Server) error { + s.Cache = redis + + return nil + } + // defer redis.Close() +} + +func WithDatabase(c *common.Config) OptionFn { + dbConn, err := db.Connect(c.DbURL) + if err != nil { + log.Fatalf("Failed to connect to the Database: %s. Err: %v\n", c.DbURL, err) + os.Exit(1) + } + + return func(s *Server) error { + s.Database = dbConn + + return nil + } + // defer dbConn.Close() +} + +func WithEventbus(c *common.Config) OptionFn { + conn, err := amqp.Dial(c.EventBusURL) + if err != nil { + log.Fatalf("Failed to connect to the Eventbus: %s. Err: %v\n", c.EventBusURL, err) + } + + chn, err := conn.Channel() + if err != nil { + log.Fatalf("Failed to open new Eventbus channel. Err: %v\n", err) + } + + return func(s *Server) error { + s.Eventbus = chn + + return nil + } + + // defer ebCh.Close() + // defer amqp.Close(ebConn) +} + +func WithLogger(c *common.Config) OptionFn { + logHost, logPort, err := fluentd.ParseAddr(c.LoggerAddr) + if err != nil { + log.Fatalf("Failed to parse Fluentd address: %s. Err: %v", c.LoggerAddr, err) + } + + logger, err := fluentd.NewLogger(c.GetAppFullName(), logHost, logPort) + if err != nil { + log.Fatalf("Failed to connect to the Fluentd on %s:%d. Err: %v", logHost, logPort, err) + } + + return func(s *Server) error { + s.Logger = logger + + return nil + } + // defer logger.Close() +} + +func WithRegistry(c *common.Config) OptionFn { + // fmt.Printf("WithRegistry constructor: config: %v", c.Base) + port, _ := strconv.Atoi(c.Base.NetAddr[1:]) // FIXME: can be IP:PORT which now will cause error + registry, err := consul.NewService(c.RegistryAddr, c.Base.AppID, c.Base.AppName, c.Base.AppID, c.Base.AppName, c.Base.PathPrefix, port) + if err != nil { + log.Fatalf("Failed to connect to the Consul on: %s. Err: %v", c.RegistryAddr, err) + } + + err = registry.Register() + if err != nil { + log.Fatalf("Failed to register in the Consul service. Err: %v", err) + } + + return func(s *Server) error { + s.Registry = registry + + go func(s *Server) { // Consul KV updater + ticker := time.NewTicker(time.Second * 15) + for range ticker.C { + s.updateKVConfig() + } + }(s) + + go func(s *Server) { // Server metadata cache updater + ticker := time.NewTicker(time.Second * 5) + for range ticker.C { + s.cacheMetadata() + } + }(s) + + return nil + } +} + +// REFACTOR IN PROGRESS +// func (s *Server) Shutdown() error { +// s.Logger.Log("Server is going down... Unregistering service: %s", s.Discovery.GetID()) +// s.Discovery.Unregister() +// s.clearMetadataCache() + +// s.Cache.Close() +// s.Database.Close() +// s.Eventbus.Close() +// s.Logger.Close() + +// return nil // } -func (s *Server) StartWithGracefulShutdown(forever chan struct{}) { - go func() { - sigint := make(chan os.Signal, 1) - signal.Notify(sigint, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - <-sigint +func (s *Server) Shutdown() srv.PurgeFn { + return func(srv *srv.Server) error { + fmt.Printf("%v", s.Base) + // s.Logger.Log("Server is going down... Unregistering service: %s", s.Base.AppID) + s.Logger.Log("Server is going down... Unregistering service...") - if err := s.gracefulShutdown(); err != nil { - s.log.Log("Server is not shutting down! Reason: %v", err) - } + s.Registry.Unregister() + s.clearMetadataCache() + s.Eventbus.Close() + s.Database.Close() + s.Logger.Close() - close(forever) - }() - - if err := s.Listen(s.addr); err != nil { - s.log.Log("Server is not running! Reason: %v", err) + return s.Base.Shutdown() } - - <-forever } -func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) { - var hdr = new(Headers) - if err := c.ReqHeaderParser(hdr); err != nil { - return "", err - } +// END: REFACTOR IN PROGRESS - return hdr.RequestID, nil -} - -func (s *Server) Error400(c *fiber.Ctx, msg string) error { - return c.Status(fiber.StatusBadRequest).JSON(&def.ErrorResponse{Error: msg}) -} - -func (s *Server) Error404(c *fiber.Ctx, msg string) error { - return c.Status(fiber.StatusNotFound).JSON(&def.ErrorResponse{Error: msg}) -} - -func (s *Server) updateKVConfig() { // FIXME: duplicated in cmd/worker/main.go - config, _, err := s.discovery.KV().Get(s.kvNmspc, nil) +// @CHECK: merge s.Config and s.Base.Config to display all config as one array/map +func (s *Server) updateKVConfig() { + config, _, err := s.Registry.KV().Get(s.kvNmspc, nil) if err != nil || config == nil { return } kvCnf := bytes.NewBuffer(config.Value) decoder := json.NewDecoder(kvCnf) - if err := decoder.Decode(&s.conf); err != nil { + if err := decoder.Decode(&s.Config); err != nil { return } } func (s *Server) cacheMetadata() { - ctx := context.Background() - key, address := s.getMetadataIPsKey(), s.conf.AppID + ctx := context.TODO() + key, address := s.getMetadataIPsKey(), s.Base.Config.AppID - pos := s.cache.LPos(ctx, key, address, redis.LPosArgs{}).Val() + pos := s.Cache.LPos(ctx, key, address, redis.LPosArgs{}).Val() if pos >= 0 { - s.cache.LRem(ctx, key, 0, address) + s.Cache.LRem(ctx, key, 0, address) } - s.cache.LPush(ctx, key, address).Err() + s.Cache.LPush(ctx, key, address).Err() } func (s *Server) clearMetadataCache() { - ctx := context.Background() - key, address := s.getMetadataIPsKey(), s.conf.AppID + ctx := context.TODO() + fmt.Printf("metadata: %v", s.Config.Base) + key, address := s.getMetadataIPsKey(), s.Config.Base.AppID - s.cache.LRem(ctx, key, 0, address) + s.Cache.LRem(ctx, key, 0, address) } func (s *Server) getMetadataIPsKey() string { - return "internal__" + s.conf.AppName + "__ips" + return "internal__" + s.Base.Config.AppName + "__ips" } -func (s *Server) gracefulShutdown() error { - s.log.Log("Server is going down... Unregistering service: %s", s.discovery.GetID()) - s.discovery.Unregister() - s.clearMetadataCache() +// +// +// +//// OLD CODE TO BE REMOVED +// func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, cache *redis.Client, ebCh *amqp.Channel) *Server { - s.ebCh.Close() - s.db.Close() - s.log.Close() +// cnf := fiber.Config{ +// AppName: conf.AppName, +// ServerHeader: conf.AppName, +// ReadTimeout: conf.ReadTimeout * time.Millisecond, +// WriteTimeout: conf.WriteTimeout * time.Millisecond, +// IdleTimeout: conf.IdleTimeout * time.Millisecond, +// } +// s := &Server{ +// fiber.New(cnf), +// conf, +// logger, +// db, +// cache, +// ebCh, +// consul, +// conf.AppName, +// conf.NetAddr, +// conf.KVNamespace, +// } - return s.Shutdown() -} +// return s +// } diff --git a/src/internal/app/service/basket.go b/src/internal/app/service/basket.go index 4c26160..12a88fb 100644 --- a/src/internal/app/service/basket.go +++ b/src/internal/app/service/basket.go @@ -15,7 +15,7 @@ import ( ) const ( - SERVICE_USER_AGENT = "basket-httpclient" + ServiceUserAgent = "basket-httpclient" ) type BasketService struct { @@ -82,7 +82,7 @@ func (s *BasketService) FetchItem(ctx context.Context, basketID string, productI func (s *BasketService) AddItem(ctx context.Context, itemID int, basketID string, qty int) error { var price float64 = 0 - pricingAPI := api.NewPricingAPI(SERVICE_USER_AGENT, s.redis) + pricingAPI := api.NewPricingAPI(ServiceUserAgent, s.redis) productPrice, err := pricingAPI.GetProductPrice(itemID) if err == nil { @@ -112,7 +112,7 @@ func (s *BasketService) RemoveItem(ctx context.Context, itemID int, basketID str func (s *BasketService) UpdateItem(ctx context.Context, item *model.BasketItemModel, qty int) error { var price float64 = 0 - pricingAPI := api.NewPricingAPI(SERVICE_USER_AGENT, s.redis) + pricingAPI := api.NewPricingAPI(ServiceUserAgent, s.redis) productPrice, err := pricingAPI.GetProductPrice(item.ProductID) if err == nil { diff --git a/src/internal/common/config.go b/src/internal/common/config.go new file mode 100644 index 0000000..ca27f70 --- /dev/null +++ b/src/internal/common/config.go @@ -0,0 +1,84 @@ +package common + +import ( + "fmt" + "os" + + cnf "git.pbiernat.dev/egommerce/basket-service/pkg/config" + srv "git.pbiernat.dev/egommerce/basket-service/pkg/server" +) + +const ( + // defAppDomain = "basket-svc" + defAppName = "basket-svc" + defCacheAddr = "api-cache:6379" + defCachePassword = "12345678" + defDbURL = "postgres://postgres:12345678@postgres-db:5432/egommerce" + defEventBusURL = "amqp://guest:guest@api-eventbus:56721" + defKVNmspc = "dev.egommerce/service/basket-svc" + defLoggerAddr = "api-logger:24224" + defNetAddr = ":80" + defMongoDbURL = "mongodb://mongodb:12345678@mongo-db:27017" + defPathPrefix = "/basket" + defRegistryAddr = "api-registry:8500" + defEbEventsExchange = "api-events" + defEbEventsQueue = "basket-svc" +) + +type Config struct { + Base *srv.Config + // AppID string + // AppName string + // NetAddr string + // PathPrefix string + + // IdleTimeout time.Duration `json:"idle_timeout"` // miliseconds + // ReadTimeout time.Duration `json:"read_timeout"` // miliseconds + // WriteTimeout time.Duration `json:"write_timeout"` // miliseconds + + DbURL string `json:"db_url"` + CacheAddr string `json:"cache_addr"` + CachePassword string `json:"cache_password"` + EventBusExchange string `json:"eventbus_exchange"` + EventBusQueue string `json:"eventbus_queue"` + EventBusURL string `json:"eventbus_url"` + LoggerAddr string `json:"logger_addr"` + RegistryAddr string + + // Fields with JSON mappings are available through Consul KV storage + + // Port int + // KVNamespace string + // MongoDbUrl string `json:"mongodb_url"` + // HttpReadTimeout int `json:"http_read_timeout"` + // HttpWriteTimeout int `json:"http_write_timeout"` + // HttpIdleTimeout int `json:"http_idle_timeout"` +} + +func NewConfig() *Config { + c := new(Config) + c.Base = new(srv.Config) + + c.Base.AppID, _ = os.Hostname() + c.Base.AppName = cnf.GetEnv("APP_NAME", defAppName) + c.Base.NetAddr = cnf.GetEnv("SERVER_ADDR", defNetAddr) + c.Base.PathPrefix = cnf.GetEnv("APP_PATH_PREFIX", defPathPrefix) + + c.CacheAddr = cnf.GetEnv("CACHE_ADDR", defCacheAddr) + c.CachePassword = cnf.GetEnv("CACHE_PASSWORD", defCachePassword) + c.DbURL = cnf.GetEnv("DATABASE_URL", defDbURL) + c.EventBusExchange = defEbEventsExchange + c.EventBusURL = cnf.GetEnv("EVENTBUS_URL", defEventBusURL) + c.LoggerAddr = cnf.GetEnv("LOGGER_ADDR", defLoggerAddr) + c.RegistryAddr = cnf.GetEnv("REGISTRY_ADDR", defRegistryAddr) + + return c +} + +func (c *Config) GetAppFullName() string { + return fmt.Sprintf("%s_%s", c.Base.AppName, c.Base.AppID) // @TODO check if Base prop can be private +} + +func (c *Config) GetListenAddr() string { + return "" // @TODO: Implement me! +} diff --git a/src/internal/app/config/env.go b/src/pkg/config/config.go similarity index 72% rename from src/internal/app/config/env.go rename to src/pkg/config/config.go index 9dbe349..67c6b43 100644 --- a/src/internal/app/config/env.go +++ b/src/pkg/config/config.go @@ -12,7 +12,7 @@ func init() { ErrLoadingEnvs = godotenv.Load() } -func GetEnv(name string, defVal string) string { // FIXME defVal and return types +func GetEnv(name string, defVal string) string { env := os.Getenv(name) if env == "" { return defVal diff --git a/src/internal/app/database/connect.go b/src/pkg/database/connect.go similarity index 100% rename from src/internal/app/database/connect.go rename to src/pkg/database/connect.go diff --git a/src/pkg/server/config.go b/src/pkg/server/config.go new file mode 100644 index 0000000..fca21d3 --- /dev/null +++ b/src/pkg/server/config.go @@ -0,0 +1,21 @@ +package server + +import ( + "fmt" + "time" +) + +type Config struct { + AppID string + AppName string + NetAddr string + PathPrefix string + + IdleTimeout time.Duration // miliseconds + ReadTimeout time.Duration // miliseconds + WriteTimeout time.Duration // miliseconds +} + +func (c *Config) GetAppFullName() string { + return fmt.Sprintf("%s_%s", c.AppName, c.AppID) +} diff --git a/src/pkg/server/server.go b/src/pkg/server/server.go new file mode 100644 index 0000000..10c7029 --- /dev/null +++ b/src/pkg/server/server.go @@ -0,0 +1,101 @@ +package server + +import ( + "fmt" + "log" + "os" + "os/signal" + "syscall" + "time" + + "github.com/gofiber/fiber/v2" + + "git.pbiernat.dev/egommerce/api-entities/http" +) + +type ( + HeaderRequestID struct { + RequestID string `reqHeader:"x-request-id"` + } + Server struct { + *fiber.App + *Config + + addr string // e.g. "127.0.0.1:8080" + + // name string // e.g. "awesome-rest-api" + // kvNmspc string + // cache *redis.Client + // db *pgxpool.Pool + // discovery *discovery.Service + // ebCh *amqp.Channel + // log *fluentd.Logger + } + PurgeFn func(*Server) error +) + +func New(conf *Config) *Server { + return &Server{ + App: fiber.New(fiber.Config{ + AppName: conf.AppID, + ServerHeader: conf.AppName, + ReadTimeout: conf.ReadTimeout * time.Millisecond, + WriteTimeout: conf.WriteTimeout * time.Millisecond, + IdleTimeout: conf.IdleTimeout * time.Millisecond, + }), + addr: conf.NetAddr, + } +} + +func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) { + var hdr = new(HeaderRequestID) + if err := c.ReqHeaderParser(hdr); err != nil { + return "", err + } + + return hdr.RequestID, nil +} + +// @Refactor make single func with error message and optional http status code... +func (s *Server) Error400(c *fiber.Ctx, msg string) error { + return c.Status(fiber.StatusBadRequest).JSON(http.ErrorResponse{msg}) + // test with &(reference) before http.ErrorMessage, but probably it's gonna be erroneous +} + +func (s *Server) Error401(c *fiber.Ctx, msg string) error { + return c.Status(fiber.StatusUnauthorized).JSON(http.ErrorResponse{msg}) +} + +func (s *Server) Error403(c *fiber.Ctx, msg string) error { + return c.Status(fiber.StatusForbidden).JSON(http.ErrorResponse{msg}) +} + +func (s *Server) Error404(c *fiber.Ctx, msg string) error { + return c.Status(fiber.StatusNotFound).JSON(http.ErrorResponse{msg}) +} + +// @EndRefactor + +func (s *Server) Start(forever chan struct{}, prgFn PurgeFn) error { + go func() { + fmt.Println("Starting...") + sigint := make(chan os.Signal, 1) + signal.Notify(sigint, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + <-sigint + + fmt.Println("shutting down: after term signal.") + if err := prgFn(s); err != nil { + log.Fatalf("Failed to shutdown server. Reason: %v\n", err) + } + + close(forever) + }() + + err := s.Listen(s.addr) + <-forever + // if err := s.Listen(s.addr); err != nil { + // s.logger.Log("Failed to start server! Reason: %v\n", err) + // } + + return err +}