From 193abd2ed7f7c3f0e4a0666edb339faac09d3d29 Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Sun, 25 Dec 2022 21:06:42 +0100 Subject: [PATCH] Refactoring --- src/cmd/migrate/main.go | 20 ++-- src/cmd/server/main.go | 17 +++- src/cmd/worker/main.go | 59 ++++++----- src/go.mod | 20 ++-- src/go.sum | 62 ++++++++---- src/internal/app/database/connect.go | 6 +- src/internal/app/definition/catalog.go | 17 ---- src/internal/app/definition/error.go | 9 -- src/internal/app/definition/health.go | 5 - src/internal/app/event/basket.go | 6 +- src/internal/app/server/catalog_handler.go | 108 ++++++++++++--------- src/internal/app/server/config.go | 3 + src/internal/app/server/health_handler.go | 2 +- src/internal/app/server/router.go | 15 +++ src/internal/app/server/server.go | 65 +++++++++---- src/internal/app/service/catalog.go | 62 +++++++++--- src/internal/app/ui/catalog.go | 63 ++++++++++++ 17 files changed, 361 insertions(+), 178 deletions(-) delete mode 100644 src/internal/app/definition/catalog.go delete mode 100644 src/internal/app/definition/error.go delete mode 100644 src/internal/app/definition/health.go create mode 100644 src/internal/app/ui/catalog.go diff --git a/src/cmd/migrate/main.go b/src/cmd/migrate/main.go index 7a6da02..cce6028 100644 --- a/src/cmd/migrate/main.go +++ b/src/cmd/migrate/main.go @@ -44,7 +44,7 @@ func main() { logger := fluentd.NewLogger(defAppName, logHost, logPort) defer logger.Close() - flag.Usage = usage + flag.Usage = usage // FIXME flag.Parse() db := pg.Connect(&pg.Options{ // FIXME @@ -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 ff98c32..1f8cdc5 100644 --- a/src/cmd/server/main.go +++ b/src/cmd/server/main.go @@ -10,15 +10,19 @@ import ( "git.pbiernat.dev/egommerce/catalog-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 = "catalog-svc" defAppDomain = "catalog-svc" + defPathPrefix = "/catalog" 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 5242366..fcdc042 100644 --- a/src/cmd/worker/main.go +++ b/src/cmd/worker/main.go @@ -18,7 +18,9 @@ import ( "git.pbiernat.dev/egommerce/catalog-service/internal/app/server" 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 ( @@ -26,6 +28,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" @@ -44,6 +48,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 @@ -53,7 +59,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) } @@ -74,16 +80,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) @@ -103,7 +117,7 @@ func main() { os.Exit(1) } - amqp.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "warehouse.catalog.stockUpdated") + rabbitmq.BindQueueToExchange(ebCh, c.EventBusQueue, c.EventBusExchange, "warehouse.catalog.stockUpdated") // if err != nil { // logger.Log("Failed to bind EventBus queue: %v\n", err) // os.Exit(1) @@ -137,25 +151,26 @@ func main() { go func() { 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 - } + go func(d amqp.Delivery) { + msg, err := rabbitmq.Deserialize(d.Body) + if err != nil { + logger.Log("json error: %v\n", err) + d.Reject(false) // FIXME: how to handle erros in queue...???? + return + } - eName := fmt.Sprintf("%s", msg["event"]) - data := (msg["data"]).(map[string]interface{}) - logger.Log("Message<%s>: %s\n", eName, data) + eName := fmt.Sprintf("%s", msg["event"]) + data := (msg["data"]).(map[string]interface{}) + logger.Log("Message<%s>: %s\n", eName, data) - switch true { - case strings.Contains(eName, event.EVENT_WAREHOUSE_STOCK_UPDATED): // todo: first create such service ;) - // update product available qty - logger.Log("Event: %s", event.EVENT_WAREHOUSE_STOCK_UPDATED) - } + switch true { + case strings.Contains(eName, event.EVENT_WAREHOUSE_STOCK_UPDATED): // todo: demo consumer... + logger.Log("Event: %s", event.EVENT_WAREHOUSE_STOCK_UPDATED) + } - 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 faff308..2389d4b 100644 --- a/src/go.mod +++ b/src/go.mod @@ -3,12 +3,15 @@ module git.pbiernat.dev/egommerce/catalog-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/google/uuid v1.3.0 - github.com/jackc/pgx/v4 v4.17.2 + github.com/jackc/pgx/v5 v5.1.1 github.com/joho/godotenv v1.4.0 github.com/streadway/amqp v1.0.0 ) @@ -16,6 +19,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 @@ -26,14 +31,13 @@ require ( 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/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.13.0 // indirect github.com/jackc/pgio v1.0.0 // 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 + 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 github.com/mattn/go-colorable v0.1.13 // indirect @@ -52,8 +56,10 @@ require ( 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 - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // 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.7 // 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 3e8abb8..f11719c 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,6 +1,12 @@ 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.133 h1:3CF/3+27SyHaYSDFBwuB9DWtU+jvf6IOuhWkhlmNrr8= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.133/go.mod h1:w2N79aoumjrrcrGPJLkCwxAHtrLd7G4Uj8VOxvPooa0= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.134 h1:ToujzrSBAD0Yt62T4+Ak+5pRCw6sMYnry3FDTo3eRnM= +git.pbiernat.dev/egommerce/go-api-pkg v0.0.134/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,11 +29,13 @@ 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= -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/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= @@ -35,6 +43,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= @@ -46,6 +56,8 @@ github.com/fluent/fluent-logger-golang v1.9.0/go.mod h1:2/HCT/jTy78yGyeNGQLGQsjF 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= 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= @@ -59,10 +71,12 @@ 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= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +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= @@ -138,6 +152,7 @@ github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4 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= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -154,7 +169,6 @@ 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/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= @@ -173,19 +187,20 @@ 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= +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/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= +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 v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= -github.com/jackc/puddle v1.3.0/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= @@ -201,8 +216,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv 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 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 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= @@ -251,18 +266,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 h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= 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= @@ -291,6 +305,7 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx 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/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= @@ -300,7 +315,6 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh 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 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= 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= @@ -351,6 +365,8 @@ 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= @@ -374,8 +390,9 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y 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-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/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= @@ -416,6 +433,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ 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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -464,8 +483,9 @@ 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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -510,8 +530,8 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks 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 h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= 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= @@ -522,8 +542,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/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/catalog.go b/src/internal/app/definition/catalog.go deleted file mode 100644 index 3a796ed..0000000 --- a/src/internal/app/definition/catalog.go +++ /dev/null @@ -1,17 +0,0 @@ -package definition - -type AddProductToBasketRequest struct { - ProductID int `json:"product_id"` -} - -type ProductAddToBasketResponse struct { - BasketID string `json:"basket_id"` -} - -type RemoveProductFromBasketRequest struct { - ProductID int `json:"product_id"` -} - -type RemoveProductFromBasketResponse struct { - BasketID string `json:"basket_id"` -} 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.go b/src/internal/app/definition/health.go deleted file mode 100644 index 6920fca..0000000 --- a/src/internal/app/definition/health.go +++ /dev/null @@ -1,5 +0,0 @@ -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 index 93f91df..7eaa747 100644 --- a/src/internal/app/event/basket.go +++ b/src/internal/app/event/basket.go @@ -7,12 +7,14 @@ const ( type ProductAddedToBasketEvent struct { *Event - ProductID string `json:"product_id"` + ProductID int `json:"product_id"` + Quantity int `json:"quantity"` BasketID string `json:"basket_id"` } type ProductRemovedFromBasketEvent struct { *Event - ProductID string `json:"product_id"` + ProductID int `json:"product_id"` + Quantity int `json:"quantity"` BasketID string `json:"basket_id"` } diff --git a/src/internal/app/server/catalog_handler.go b/src/internal/app/server/catalog_handler.go index 20a09ac..3de2527 100644 --- a/src/internal/app/server/catalog_handler.go +++ b/src/internal/app/server/catalog_handler.go @@ -1,15 +1,77 @@ package server import ( - "strconv" + "fmt" "github.com/gofiber/fiber/v2" "github.com/google/uuid" - def "git.pbiernat.dev/egommerce/catalog-service/internal/app/definition" + def "git.pbiernat.dev/egommerce/api-entities/http" "git.pbiernat.dev/egommerce/catalog-service/internal/app/service" + "git.pbiernat.dev/egommerce/catalog-service/internal/app/ui" ) +func (s *Server) GetProductListHandler(c *fiber.Ctx) error { + reqID, _ := s.GetRequestID(c) + req := new(def.GetProductListRequest) + catalogSrv := service.NewCatalogService(s.db, s.ebCh, s.log) + res, err := ui.GetProductList(catalogSrv, req.CategoryID, reqID) + if err != nil { + return err + } + + return c.JSON(res) +} + +func (s *Server) AddProductToBasketHandler(c *fiber.Ctx) error { + reqID, _ := s.GetRequestID(c) + req := new(def.AddProductToBasketRequest) + if err := c.BodyParser(req); err != nil { + return s.Error400(c, err.Error()) + } + + basketID := prepareBasket(c) + qty := 1 + if req.Quantity != 0 { + qty = req.Quantity + } + + catalogSrv := service.NewCatalogService(s.db, s.ebCh, s.log) + res, err := ui.AddProductToBasket(catalogSrv, req.ProductID, qty, basketID, reqID) + if err != nil { + s.log.Log("AddProductToBasketHandler error: ", err) + if res.ProductID == 0 { + return s.Error404(c, fmt.Sprintf("Product #%d not exists", req.ProductID)) + } + return s.Error400(c, "Failed to add product to basket") + } + + return c.JSON(res) +} + +func (s *Server) RemoveProductFromBasketHandler(c *fiber.Ctx) error { + reqID, _ := s.GetRequestID(c) + req := new(def.RemoveProductFromBasketRequest) + if err := c.BodyParser(req); err != nil { + return s.Error400(c, err.Error()) + } + + basketID := prepareBasket(c) + qty := 1 + if req.Quantity != 0 { + qty = req.Quantity + } + + catalogSrv := service.NewCatalogService(s.db, s.ebCh, s.log) + res, err := ui.RemoveProductFromBasket(catalogSrv, req.ProductID, qty, basketID, reqID) + if err != nil { + s.log.Log("RemoveProductFromBasketHandler error: ", err) + return s.Error400(c, "Failed to remove product from basket") + } + + return c.JSON(res) +} + func prepareBasket(c *fiber.Ctx) string { basketID := c.Cookies(service.BasketIdCookieName) if len(basketID) == 0 { @@ -19,45 +81,3 @@ func prepareBasket(c *fiber.Ctx) string { return basketID } - -func (s *Server) AddProductToBasketHandler(c *fiber.Ctx) error { - reqID, _ := s.GetRequestID(c) - data := new(def.AddProductToBasketRequest) - if err := c.BodyParser(data); err != nil { - return err - } - - productID := strconv.Itoa(data.ProductID) - // vlaidate, pre check... etc - - basketID := prepareBasket(c) - catalog := service.NewCatalogService(s.ebCh, s.log) - if err := catalog.AddProductToBasket(reqID, productID, basketID); err != nil { - return err - } - - return c.JSON(&def.ProductAddToBasketResponse{ - BasketID: basketID, - }) -} - -func (s *Server) RemoveProductFromBasketHandler(c *fiber.Ctx) error { - reqID, _ := s.GetRequestID(c) - data := new(def.RemoveProductFromBasketRequest) - if err := c.BodyParser(data); err != nil { - return err - } - - productID := strconv.Itoa(data.ProductID) - // vlaidate, pre check... etc - - basketID := prepareBasket(c) - catalog := service.NewCatalogService(s.ebCh, s.log) - if err := catalog.RemoveProductFromBasket(reqID, productID, basketID); err != nil { - return err - } - - return c.JSON(&def.RemoveProductFromBasketResponse{ - BasketID: basketID, - }) -} 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 148b553..05b27b3 100644 --- a/src/internal/app/server/health_handler.go +++ b/src/internal/app/server/health_handler.go @@ -1,7 +1,7 @@ package server import ( - def "git.pbiernat.dev/egommerce/catalog-service/internal/app/definition" + def "git.pbiernat.dev/egommerce/api-entities/http" "github.com/gofiber/fiber/v2" ) diff --git a/src/internal/app/server/router.go b/src/internal/app/server/router.go index 6d7c50f..be5a792 100644 --- a/src/internal/app/server/router.go +++ b/src/internal/app/server/router.go @@ -5,19 +5,34 @@ import ( "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("/product", s.GetProductListHandler) + // v1.Get("/product/:productId", s.GetProductHandler) v1.Post("/product", s.AddProductToBasketHandler) v1.Delete("/product", s.RemoveProductFromBasketHandler) } func SetupMiddlewares(s *Server) { + s.App.Use(defaultCORS) s.App.Use(LoggingMiddleware(s.log)) } diff --git a/src/internal/app/server/server.go b/src/internal/app/server/server.go index e3dc80e..282f0cf 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/v4/pgxpool" + "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,8 +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 { - 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) } @@ -58,6 +60,7 @@ func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amq conf, logger, db, + cache, ebCh, consul, conf.AppName, @@ -66,13 +69,21 @@ func NewServer(conf *Config, logger *fluentd.Logger, db *pgxpool.Pool, ebCh *amq } go func(s *Server) { // Consul KV config updater - interval := time.Second * 30 + 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 +125,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/catalog.go b/src/internal/app/service/catalog.go index eff455d..4cb784d 100644 --- a/src/internal/app/service/catalog.go +++ b/src/internal/app/service/catalog.go @@ -1,10 +1,15 @@ package service import ( + "context" + + "git.pbiernat.dev/egommerce/api-entities/model" "git.pbiernat.dev/egommerce/catalog-service/internal/app/event" "git.pbiernat.dev/egommerce/go-api-pkg/fluentd" - amqp "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" - base "github.com/streadway/amqp" + "git.pbiernat.dev/egommerce/go-api-pkg/rabbitmq" + "github.com/georgysavva/scany/v2/pgxscan" + "github.com/jackc/pgx/v5/pgxpool" + "github.com/streadway/amqp" ) const ( @@ -12,30 +17,57 @@ const ( ) type CatalogService struct { - ebCh *base.Channel - log *fluentd.Logger + dbConn *pgxpool.Pool + ebCh *amqp.Channel + log *fluentd.Logger } -func NewCatalogService(chn *base.Channel, log *fluentd.Logger) *CatalogService { - return &CatalogService{chn, log} +func NewCatalogService(dbConn *pgxpool.Pool, chn *amqp.Channel, log *fluentd.Logger) *CatalogService { + return &CatalogService{dbConn, chn, log} } -func (s *CatalogService) AddProductToBasket(reqID, productID, basketID string) error { - s.log.Log("Added product#%s to the basket#%s", productID, basketID) +func (s *CatalogService) GetProduct(ctx context.Context, reqID string, productID int) (*model.ProductModel, error) { + product := new(model.ProductModel) + err := pgxscan.Get(ctx, s.dbConn, product, `SELECT id, pid, name, price FROM catalog.product WHERE id=$1`, productID) + if err != nil { + return nil, err + } - msg := &event.ProductAddedToBasketEvent{Event: event.NewEvent(reqID), BasketID: basketID, ProductID: productID} - amqp.Publish(s.ebCh, "api-events", "catalog.basket.productAddedToBasket", msg) - amqp.Publish(s.ebCh, "api-events", "catalog.warehouse.productAddedToBasket", msg) + return product, nil // FIXME +} + +func (s *CatalogService) GetProductList(ctx context.Context, reqID string, categoryID int) ([]*model.ProductModel, error) { + products := []*model.ProductModel{} + + sql := `SELECT id, pid, name, price FROM catalog.product` + rows, err := s.dbConn.Query(ctx, sql) //, categoryID + if err != nil { + return nil, err + } + + if err := pgxscan.ScanAll(&products, rows); err != nil { + return nil, err + } + + return products, nil // FIXME +} + +func (s *CatalogService) AddProductToBasket(reqID, basketID string, productID, qty int) error { + s.log.Log("Adding product #%d to the basket #%s", productID, basketID) + + msg := &event.ProductAddedToBasketEvent{Event: event.NewEvent(reqID), BasketID: basketID, ProductID: productID, Quantity: qty} + rabbitmq.Publish(s.ebCh, "api-events", "catalog.basket.productAddedToBasket", msg) + rabbitmq.Publish(s.ebCh, "api-events", "catalog.warehouse.productAddedToBasket", msg) return nil } -func (s *CatalogService) RemoveProductFromBasket(reqID, productID, basketID string) error { +func (s *CatalogService) RemoveProductFromBasket(reqID, basketID string, productID, qty int) error { s.log.Log("Removed product#%s from basket#%s", productID, basketID) - msg := &event.ProductRemovedFromBasketEvent{Event: event.NewEvent(reqID), BasketID: basketID, ProductID: productID} - amqp.Publish(s.ebCh, "api-events", "catalog.basket.productRemovedFromBasket", msg) - amqp.Publish(s.ebCh, "api-events", "catalog.warehouse.productRemovedFromBasket", msg) + msg := &event.ProductRemovedFromBasketEvent{Event: event.NewEvent(reqID), BasketID: basketID, ProductID: productID, Quantity: qty} + rabbitmq.Publish(s.ebCh, "api-events", "catalog.basket.productRemovedFromBasket", msg) + rabbitmq.Publish(s.ebCh, "api-events", "catalog.warehouse.productRemovedFromBasket", msg) return nil } diff --git a/src/internal/app/ui/catalog.go b/src/internal/app/ui/catalog.go new file mode 100644 index 0000000..e8742c6 --- /dev/null +++ b/src/internal/app/ui/catalog.go @@ -0,0 +1,63 @@ +package ui + +import ( + "context" + "time" + + def "git.pbiernat.dev/egommerce/api-entities/http" + "git.pbiernat.dev/egommerce/catalog-service/internal/app/service" +) + +func GetProductList(srv *service.CatalogService, categoryID int, reqID string) ([]def.GetProductResponse, error) { + ctx := context.Background() + res := []def.GetProductResponse{} + + products, err := srv.GetProductList(ctx, reqID, categoryID) + if err != nil { + return nil, err + } + + for _, v := range products { + product := def.GetProductResponse{ + ID: v.ID, + PID: v.PID, + Name: v.Name, + Price: v.Price, + CreatedAt: time.Duration(v.CreatedAt.Time.Unix()), + } + if v.UpdatedAt.Time.Unix() > 0 { + product.UpdatedAt = time.Duration(v.UpdatedAt.Time.Unix()) + } + res = append(res, product) + } + + return res, nil +} + +func AddProductToBasket(srv *service.CatalogService, productID, qty int, basketID, reqID string) (*def.AddProductToBasketResponse, error) { + ctx := context.Background() + res := &def.AddProductToBasketResponse{ProductID: 0} + + product, err := srv.GetProduct(ctx, reqID, productID) + if err != nil { + return res, err + } + res.ProductID = product.ID + + if err := srv.AddProductToBasket(reqID, basketID, productID, qty); err != nil { + return res, err + } + res.BasketID = basketID + + return res, nil +} + +func RemoveProductFromBasket(srv *service.CatalogService, productID, qty int, basketID, reqID string) (*def.RemoveProductFromBasketResponse, error) { + res := &def.RemoveProductFromBasketResponse{} + if err := srv.RemoveProductFromBasket(reqID, basketID, productID, qty); err != nil { + return res, err + } + res.BasketID = basketID + + return res, nil +}