From d7e827bb438a017386355473446fa19f05fac5f4 Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Tue, 5 Dec 2023 23:31:10 +0300 Subject: [PATCH 01/21] TP-c01_ci-cd: add Dockerfiles for nginx and microservices, add service deps,healthchecks --- deployments/Dockerfile.auth | 20 +++++++ deployments/Dockerfile.main | 21 +++++++ deployments/Dockerfile.messenger | 20 +++++++ deployments/Dockerfile.realtime | 20 +++++++ deployments/docker-compose.yml | 95 +++++++++++++++++++++++++++++++- 5 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 deployments/Dockerfile.auth create mode 100644 deployments/Dockerfile.main create mode 100644 deployments/Dockerfile.messenger create mode 100644 deployments/Dockerfile.realtime diff --git a/deployments/Dockerfile.auth b/deployments/Dockerfile.auth new file mode 100644 index 0000000..88735ef --- /dev/null +++ b/deployments/Dockerfile.auth @@ -0,0 +1,20 @@ +FROM golang:1.19.13-alpine AS build + +RUN apk --no-cache add make + +WORKDIR /pinspire_auth + +COPY go.mod go.sum /pinspire_auth/ +RUN go mod download + +COPY . . + +RUN make build_auth + +FROM alpine:latest + +WORKDIR / + +COPY --from=build /pinspire_auth/bin/auth . + +ENTRYPOINT [ "./auth" ] diff --git a/deployments/Dockerfile.main b/deployments/Dockerfile.main new file mode 100644 index 0000000..c595010 --- /dev/null +++ b/deployments/Dockerfile.main @@ -0,0 +1,21 @@ +FROM golang:1.19.13-alpine AS build + +RUN apk --no-cache add make + +WORKDIR /pinspire_main + +COPY go.mod go.sum /pinspire_main/ +RUN go mod download + +COPY . . + +RUN make build + +FROM alpine:latest + +WORKDIR / + +COPY --from=build /pinspire_main/bin/app . +COPY --from=build /pinspire_main/configs configs + +ENTRYPOINT [ "./app" ] diff --git a/deployments/Dockerfile.messenger b/deployments/Dockerfile.messenger new file mode 100644 index 0000000..6fa332f --- /dev/null +++ b/deployments/Dockerfile.messenger @@ -0,0 +1,20 @@ +FROM golang:1.19.13-alpine AS build + +RUN apk --no-cache add make + +WORKDIR /pinspire_messenger + +COPY go.mod go.sum /pinspire_messenger/ +RUN go mod download + +COPY . . + +RUN make build_messenger + +FROM alpine:latest + +WORKDIR / + +COPY --from=build /pinspire_messenger/bin/messenger . + +ENTRYPOINT [ "./messenger" ] diff --git a/deployments/Dockerfile.realtime b/deployments/Dockerfile.realtime new file mode 100644 index 0000000..7c94295 --- /dev/null +++ b/deployments/Dockerfile.realtime @@ -0,0 +1,20 @@ +FROM golang:1.19.13-alpine AS build + +RUN apk --no-cache add make + +WORKDIR /pinspire_realtime + +COPY go.mod go.sum /pinspire_realtime/ +RUN go mod download + +COPY . . + +RUN make build_realtime + +FROM alpine:latest + +WORKDIR / + +COPY --from=build /pinspire_realtime/bin/realtime . + +ENTRYPOINT [ "./realtime" ] diff --git a/deployments/docker-compose.yml b/deployments/docker-compose.yml index 8ee69d6..094bbab 100644 --- a/deployments/docker-compose.yml +++ b/deployments/docker-compose.yml @@ -1,5 +1,6 @@ version: '3.8' + services: postgres: image: postgres:latest @@ -10,6 +11,8 @@ services: - ../db/migrations:/docker-entrypoint-initdb.d ports: - 5432:5432 + healthcheck: + test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}"] redis: image: redis:latest @@ -19,6 +22,82 @@ services: command: redis-server /usr/local/etc/redis/redis.conf ports: - 6379:6379 + healthcheck: + test: ["CMD", "redis-cli", "ping"] + + main_service: + build: + context: ./.. + dockerfile: deployments/Dockerfile.main + container_name: pinspireMainService + env_file: + - ../.env + environment: + - POSTGRES_HOST=postgres + - AUTH_SERVICE_HOST=auth_service + - MESSENGER_SERVICE_HOST=messenger_service + - REALTIME_SERVICE_HOST=realtime_service + depends_on: + postgres: + condition: 'service_healthy' + auth_service: + condition: 'service_started' + messenger_service: + condition: 'service_started' + realtime_service: + condition: 'service_started' + ports: + - 8100:8080 + + auth_service: + build: + context: ./.. + dockerfile: deployments/Dockerfile.auth + container_name: pinspireAuthService + env_file: + - ../.env + environment: + - POSTGRES_HOST=postgres + - REDIS_HOST=redis + depends_on: + postgres: + condition: 'service_healthy' + redis: + condition: 'service_healthy' + ports: + - 8086:8086 + # - 8101:8085 + + messenger_service: + build: + context: ./.. + dockerfile: deployments/Dockerfile.messenger + container_name: pinspireMessengerService + env_file: + - ../.env + environment: + - POSTGRES_HOST=postgres + depends_on: + postgres: + condition: 'service_healthy' + ports: + - 8096:8096 + # - 8102:8095 + + realtime_service: + build: + context: ./.. + dockerfile: deployments/Dockerfile.realtime + container_name: pinspireRealtimeService + env_file: + - ../.env + environment: + - KAFKA_BROKER_ADDRESS=kafka + depends_on: + - kafka + ports: + - 8091:8091 + # - 8103:8090 zookeeper: image: bitnami/zookeeper:latest @@ -41,7 +120,7 @@ services: - ALLOW_PLAINTEXT_LISTENER=yes - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092 - - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 + - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://:9092 depends_on: - zookeeper @@ -56,6 +135,8 @@ services: grafana: image: grafana/grafana:latest container_name: pinspireGrafana + env_file: + - ../.env ports: - 3000:3000 volumes: @@ -75,6 +156,18 @@ services: - /:/rootfs:ro ports: - "9100:9100" + + nginx: + image: nginx:latest + container_name: pinspireNginx + volumes: + - '/etc/nginx/sites-available/pinspire.conf:/etc/nginx/conf.d/pinspire.conf:ro' + network_mode: 'host' + depends_on: + main_service: + condition: 'service_started' + realtime_service: + condition: 'service_started' volumes: From f8ec2a3eef23016170bfe649c7613b64a121173f Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Tue, 5 Dec 2023 23:33:22 +0300 Subject: [PATCH 02/21] TP-c01_ci-cd: changed prometheus targets, servers addresses from localhost: to :, replaced string servers params with env variables --- cmd/app/config.go | 8 ++++++-- cmd/auth/config.go | 2 +- cmd/realtime/main.go | 2 +- configs/config.yml | 2 +- configs/prometheus.yml | 10 +++++----- internal/app/app.go | 4 +++- internal/app/auth/auth.go | 13 +++++++++---- internal/app/config.go | 8 ++++---- internal/app/messenger/messenger.go | 2 +- internal/app/redis_conn.go | 2 +- internal/microservices/realtime/node.go | 4 +++- internal/pkg/delivery/websocket/websocket.go | 4 +++- 12 files changed, 38 insertions(+), 23 deletions(-) diff --git a/cmd/app/config.go b/cmd/app/config.go index 0cb9a84..42f8ed3 100644 --- a/cmd/app/config.go +++ b/cmd/app/config.go @@ -1,8 +1,12 @@ package main -import "github.com/go-park-mail-ru/2023_2_OND_team/internal/app" +import ( + "os" + + "github.com/go-park-mail-ru/2023_2_OND_team/internal/app" +) var configFiles = app.ConfigFiles{ ServerConfigFile: "configs/config.yml", - AddrAuthServer: "localhost:8085", + AddrAuthServer: os.Getenv("AUTH_SERVICE_HOST") + ":" + os.Getenv("AUTH_SERVICE_PORT"), // "localhost:8085", } diff --git a/cmd/auth/config.go b/cmd/auth/config.go index bf1142d..2ffd53a 100644 --- a/cmd/auth/config.go +++ b/cmd/auth/config.go @@ -3,6 +3,6 @@ package main import "github.com/go-park-mail-ru/2023_2_OND_team/internal/app/auth" var configAuth = auth.Config{ - Addr: "localhost:8085", + Addr: "0.0.0.0:8085", RedisFileConfig: "redis.conf", } diff --git a/cmd/realtime/main.go b/cmd/realtime/main.go index a68532f..1022c65 100644 --- a/cmd/realtime/main.go +++ b/cmd/realtime/main.go @@ -13,7 +13,7 @@ import ( "github.com/go-park-mail-ru/2023_2_OND_team/pkg/logger" ) -const _address = "localhost:8090" +const _address = "0.0.0.0:8090" func main() { log, err := logger.New() diff --git a/configs/config.yml b/configs/config.yml index 88ea0c1..4d1fda6 100644 --- a/configs/config.yml +++ b/configs/config.yml @@ -1,6 +1,6 @@ app: server: - host: 127.0.0.1 + host: 0.0.0.0 port: 8080 https: false certFile: /home/ond_team/cert/fullchain.pem diff --git a/configs/prometheus.yml b/configs/prometheus.yml index 255697d..57406b3 100644 --- a/configs/prometheus.yml +++ b/configs/prometheus.yml @@ -5,23 +5,23 @@ global: scrape_configs: - job_name: 'api' static_configs: - - targets: ['host.docker.internal:8080'] + - targets: ['main_service:8080'] - job_name: 'auth' static_configs: - - targets: ['pinspire.online:8086'] + - targets: ['auth_service:8086'] - job_name: 'messenger' static_configs: - - targets: ['pinspire.online:8096'] + - targets: ['messenger_service:8096'] - job_name: 'realtime' static_configs: - - targets: ['pinspire.online:8091'] + - targets: ['realtime_service:8091'] - job_name: 'node_exporter' static_configs: - - targets: ['pinspire.online:9100'] + - targets: ['node_exporter:9100'] - job_name: 'pinspire' scheme: https diff --git a/internal/app/app.go b/internal/app/app.go index 0437156..5d3d18f 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -2,6 +2,7 @@ package app import ( "context" + "os" "time" "github.com/joho/godotenv" @@ -57,7 +58,8 @@ func Run(ctx context.Context, log *log.Logger, cfg ConfigFiles) { } defer pool.Close() - connMessMS, err := grpc.Dial("localhost:8095", grpc.WithTransportCredentials(insecure.NewCredentials())) + // connMessMS, err := grpc.Dial("localhost:8095", grpc.WithTransportCredentials(insecure.NewCredentials())) + connMessMS, err := grpc.Dial(os.Getenv("MESSENGER_SERVICE_HOST")+":"+os.Getenv("MESSENGER_SERVICE_PORT"), grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Error(err.Error()) return diff --git a/internal/app/auth/auth.go b/internal/app/auth/auth.go index cfcfbd6..ddfc24e 100644 --- a/internal/app/auth/auth.go +++ b/internal/app/auth/auth.go @@ -3,6 +3,7 @@ package auth import ( "context" "net" + "os" "time" "github.com/joho/godotenv" @@ -54,11 +55,15 @@ func Run(ctx context.Context, log *logger.Logger, cfg Config) { ctxRedis, cancelCtxRedis := context.WithTimeout(ctx, _timeoutForConnRedis) defer cancelCtxRedis() - redisCfg, err := app.NewConfig(cfg.RedisFileConfig) - if err != nil { - log.Error(err.Error()) - return + // redisCfg, err := app.NewConfig(cfg.RedisFileConfig) + redisCfg := app.RedisConfig{ + Addr: os.Getenv("REDIS_HOST") + ":" + os.Getenv("REDIS_PORT"), + Password: os.Getenv("REDIS_PASSWORD"), } + // if err != nil { + // log.Error(err.Error()) + // return + // } redisCl, err := app.NewRedisClient(ctxRedis, redisCfg) if err != nil { diff --git a/internal/app/config.go b/internal/app/config.go index 7fa6c87..4fb3bb2 100644 --- a/internal/app/config.go +++ b/internal/app/config.go @@ -11,18 +11,18 @@ type ConfigFiles struct { AddrAuthServer string } -type redisConfig struct { +type RedisConfig struct { Password string Addr string } -func NewConfig(filename string) (redisConfig, error) { +func NewConfig(filename string) (RedisConfig, error) { cfg, err := config.ParseConfig(filename) if err != nil { - return redisConfig{}, fmt.Errorf("new redis config: %w", err) + return RedisConfig{}, fmt.Errorf("new redis config: %w", err) } - return redisConfig{ + return RedisConfig{ Password: cfg.Get("requirepass"), Addr: cfg.Get("host") + ":" + cfg.Get("port"), }, nil diff --git a/internal/app/messenger/messenger.go b/internal/app/messenger/messenger.go index f57c930..27ca153 100644 --- a/internal/app/messenger/messenger.go +++ b/internal/app/messenger/messenger.go @@ -48,7 +48,7 @@ func Run(ctx context.Context, log *logger.Logger) { )) messenger.RegisterMessengerServer(server, messMS.New(log, messageCase)) - l, err := net.Listen("tcp", "localhost:8095") + l, err := net.Listen("tcp", "0.0.0.0:8095") if err != nil { log.Error(err.Error()) return diff --git a/internal/app/redis_conn.go b/internal/app/redis_conn.go index 8a7527c..8ee910e 100644 --- a/internal/app/redis_conn.go +++ b/internal/app/redis_conn.go @@ -7,7 +7,7 @@ import ( redis "github.com/redis/go-redis/v9" ) -func NewRedisClient(ctx context.Context, cfg redisConfig) (*redis.Client, error) { +func NewRedisClient(ctx context.Context, cfg RedisConfig) (*redis.Client, error) { redisCl := redis.NewClient(&redis.Options{ Addr: cfg.Addr, Password: cfg.Password, diff --git a/internal/microservices/realtime/node.go b/internal/microservices/realtime/node.go index db17bf6..f6f39c7 100644 --- a/internal/microservices/realtime/node.go +++ b/internal/microservices/realtime/node.go @@ -2,6 +2,7 @@ package realtime import ( "fmt" + "os" "sync" "google.golang.org/protobuf/proto" @@ -20,7 +21,8 @@ func NewNode() (*Node, error) { node := &Node{} broker, err := NewKafkaBroker(node, KafkaConfig{ - Addres: []string{"localhost:9092"}, + // Addres: []string{"localhost:9092"}, + Addres: []string{os.Getenv("KAFKA_BROKER_ADDRESS") + ":" + os.Getenv("KAFKA_BROKER_PORT")}, PartitionsOnTopic: _numWorkers, MaxNumTopic: 10, }) diff --git a/internal/pkg/delivery/websocket/websocket.go b/internal/pkg/delivery/websocket/websocket.go index 6074730..c0042de 100644 --- a/internal/pkg/delivery/websocket/websocket.go +++ b/internal/pkg/delivery/websocket/websocket.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "os" "time" "google.golang.org/grpc" @@ -36,7 +37,8 @@ func SetOriginPatterns(patterns []string) Option { } func New(log *log.Logger, mesCase usecase.Usecase, opts ...Option) *HandlerWebSocket { - gRPCConn, err := grpc.Dial("localhost:8090", grpc.WithTransportCredentials(insecure.NewCredentials())) + // gRPCConn, err := grpc.Dial("localhost:8090", grpc.WithTransportCredentials(insecure.NewCredentials())) + gRPCConn, err := grpc.Dial(os.Getenv("REALTIME_SERVICE_HOST"+":"+os.Getenv("REALTIME_SERVICE_PORT")), grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Error(fmt.Errorf("grpc dial: %w", err).Error()) } From f862979bc2f69d009ffdde11aee7077ca306c7ee Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Thu, 7 Dec 2023 21:03:48 +0300 Subject: [PATCH 03/21] TP-c01_ci-cd: add linter configuration --- Makefile | 18 +++- configs/.golangci.yml | 206 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 configs/.golangci.yml diff --git a/Makefile b/Makefile index 7b0652c..ee03e17 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ .PHONY: build run test test_with_coverage cleantest retest doc generate cover_all currcover -.PHONY: build_auth build_realtime build_messenger +.PHONY: build_auth build_realtime build_messenger build_all +.PHONY: .install-linter lint lint-fast ENTRYPOINT=cmd/app/main.go DOC_DIR=./docs @@ -7,6 +8,11 @@ COV_OUT=coverage.out COV_HTML=coverage.html CURRCOVER=github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1 +PROJECT_DIR = $(shell pwd) +PROJECT_BIN = $(PROJECT_DIR)/bin +$(shell [ -f bin ] || mkdir -p $(PROJECT_BIN)) +GOLANGCI_LINT = $(PROJECT_BIN)/golangci-lint + build: go build -o bin/app cmd/app/*.go @@ -19,6 +25,8 @@ build_realtime: build_messenger: go build -o bin/messenger cmd/messenger/*.go +build_all: build build_auth build_realtime build_messenger + run: build ./bin/app @@ -51,3 +59,11 @@ currcover: go test -cover -v -coverprofile=cover.out ${CURRCOVER} go tool cover -html=cover.out -o cover.html +.install-linter: + [ -f $(PROJECT_BIN)/golangci-lint ] || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(PROJECT_BIN) v1.55.2 + +lint: .install-linter + $(GOLANGCI_LINT) run ./... --config=configs/.golangci.yml + +lint-fast: .install-linter + $(GOLANGCI_LINT) run ./... --fast --config=configs/.golangci.yml diff --git a/configs/.golangci.yml b/configs/.golangci.yml new file mode 100644 index 0000000..cac2d04 --- /dev/null +++ b/configs/.golangci.yml @@ -0,0 +1,206 @@ +# This code is licensed under the terms of the MIT license https://opensource.org/license/mit +# Copyright (c) 2021 Marat Reymers + +## Golden config for golangci-lint v1.55.2 +# +# This is the best config for golangci-lint based on my experience and opinion. +# It is very strict, but not extremely strict. +# Feel free to adapt and change it for your needs. + +run: + # Timeout for analysis, e.g. 30s, 5m. + # Default: 1m + timeout: 3m + skip-dirs: + - .. + + + +# This file contains only configs which differ from defaults. +# All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml +linters-settings: + cyclop: + # The maximal code complexity to report. + # Default: 10 + max-complexity: 30 + # The maximal average package complexity. + # If it's higher than 0.0 (float) the check is enabled + # Default: 0.0 + package-average: 10.0 + + errcheck: + # Report about not checking of errors in type assertions: `a := b.(MyStruct)`. + # Such cases aren't reported by default. + # Default: false + check-type-assertions: true + + exhaustive: + # Program elements to check for exhaustiveness. + # Default: [ switch ] + check: + - switch + - map + + exhaustruct: + # List of regular expressions to exclude struct packages and names from check. + # Default: [] + exclude: + # std libs + - "^net/http.Client$" + - "^net/http.Cookie$" + - "^net/http.Request$" + - "^net/http.Response$" + - "^net/http.Server$" + - "^net/http.Transport$" + - "^net/url.URL$" + - "^os/exec.Cmd$" + - "^reflect.StructField$" + # public libs + - "^github.com/Shopify/sarama.Config$" + - "^github.com/Shopify/sarama.ProducerMessage$" + - "^github.com/mitchellh/mapstructure.DecoderConfig$" + - "^github.com/prometheus/client_golang/.+Opts$" + - "^github.com/spf13/cobra.Command$" + - "^github.com/spf13/cobra.CompletionOptions$" + - "^github.com/stretchr/testify/mock.Mock$" + - "^github.com/testcontainers/testcontainers-go.+Request$" + - "^github.com/testcontainers/testcontainers-go.FromDockerfile$" + - "^golang.org/x/tools/go/analysis.Analyzer$" + - "^google.golang.org/protobuf/.+Options$" + - "^gopkg.in/yaml.v3.Node$" + + funlen: + # Checks the number of lines in a function. + # If lower than 0, disable the check. + # Default: 60 + lines: 100 + # Checks the number of statements in a function. + # If lower than 0, disable the check. + # Default: 40 + statements: 50 + # Ignore comments when counting lines. + # Default false + ignore-comments: true + + gocognit: + # Minimal code complexity to report. + # Default: 30 (but we recommend 10-20) + min-complexity: 20 + + gocritic: + # Settings passed to gocritic. + # The settings key is the name of a supported gocritic checker. + # The list of supported checkers can be find in https://go-critic.github.io/overview. + settings: + captLocal: + # Whether to restrict checker to params only. + # Default: true + paramsOnly: false + underef: + # Whether to skip (*x).method() calls where x is a pointer receiver. + # Default: true + skipRecvDeref: false + + gomnd: + # List of function patterns to exclude from analysis. + # Values always ignored: `time.Date`, + # `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`, + # `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`. + # Default: [] + ignored-functions: + - flag.Arg + - flag.Duration.* + - flag.Float.* + - flag.Int.* + - flag.Uint.* + - os.Chmod + - os.Mkdir.* + - os.OpenFile + - os.WriteFile + - prometheus.ExponentialBuckets.* + - prometheus.LinearBuckets + + gomodguard: + blocked: + # List of blocked modules. + # Default: [] + modules: + - github.com/golang/protobuf: + recommendations: + - google.golang.org/protobuf + reason: "see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules" + - github.com/satori/go.uuid: + recommendations: + - github.com/google/uuid + reason: "satori's package is not maintained" + - github.com/gofrs/uuid: + recommendations: + - github.com/google/uuid + reason: "gofrs' package is not go module" + + govet: + # Enable all analyzers. + # Default: false + enable-all: true + # Disable analyzers by name. + # Run `go tool vet help` to see all analyzers. + # Default: [] + disable: + - fieldalignment # too strict + # Settings per analyzer. + settings: + shadow: + # Whether to be strict about shadowing; can be noisy. + # Default: false + strict: true + + nakedret: + # Make an issue if func has more lines of code than this setting, and it has naked returns. + # Default: 30 + max-func-lines: 0 + + nolintlint: + # Exclude following linters from requiring an explanation. + # Default: [] + allow-no-explanation: [ funlen, gocognit, lll ] + # Enable to require an explanation of nonzero length after each nolint directive. + # Default: false + require-explanation: true + # Enable to require nolint directives to mention the specific linter being suppressed. + # Default: false + require-specific: true + + rowserrcheck: + # database/sql is always checked + # Default: [] + packages: + - github.com/jmoiron/sqlx + + tenv: + # The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures. + # Otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked. + # Default: false + all: true + + +issues: + # Maximum count of issues with the same text. + # Set to 0 to disable. + # Default: 3 + exclude-use-default: true + max-same-issues: 50 + + exclude-rules: + - source: "(noinspection|TODO)" + linters: [ godot ] + - source: "//noinspection" + linters: [ gocritic ] + - path: "_test\\.go" + linters: + - bodyclose + - dupl + - funlen + - goconst + - gosec + - noctx + - wrapcheck \ No newline at end of file From ea75fda9e0de36917c696dc38bb50a1425387fad Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Thu, 7 Dec 2023 21:22:28 +0300 Subject: [PATCH 04/21] TP-c01_ci-cd: add named volumes for postgres and redis, add compose.prod.yml for pulling images while deploying --- deployments/Dockerfile.auth | 6 +++--- deployments/Dockerfile.main | 8 ++++---- deployments/Dockerfile.messenger | 6 +++--- deployments/Dockerfile.realtime | 6 +++--- deployments/compose.prod.yml | 14 ++++++++++++++ deployments/docker-compose.yml | 12 ++++++++---- 6 files changed, 35 insertions(+), 17 deletions(-) create mode 100644 deployments/compose.prod.yml diff --git a/deployments/Dockerfile.auth b/deployments/Dockerfile.auth index 88735ef..74b9443 100644 --- a/deployments/Dockerfile.auth +++ b/deployments/Dockerfile.auth @@ -2,9 +2,9 @@ FROM golang:1.19.13-alpine AS build RUN apk --no-cache add make -WORKDIR /pinspire_auth +WORKDIR /pinspire -COPY go.mod go.sum /pinspire_auth/ +COPY go.mod go.sum /pinspire/ RUN go mod download COPY . . @@ -15,6 +15,6 @@ FROM alpine:latest WORKDIR / -COPY --from=build /pinspire_auth/bin/auth . +COPY --from=build /pinspire/bin/auth . ENTRYPOINT [ "./auth" ] diff --git a/deployments/Dockerfile.main b/deployments/Dockerfile.main index c595010..4d500c8 100644 --- a/deployments/Dockerfile.main +++ b/deployments/Dockerfile.main @@ -2,9 +2,9 @@ FROM golang:1.19.13-alpine AS build RUN apk --no-cache add make -WORKDIR /pinspire_main +WORKDIR /pinspire -COPY go.mod go.sum /pinspire_main/ +COPY go.mod go.sum /pinspire/ RUN go mod download COPY . . @@ -15,7 +15,7 @@ FROM alpine:latest WORKDIR / -COPY --from=build /pinspire_main/bin/app . -COPY --from=build /pinspire_main/configs configs +COPY --from=build /pinspire/bin/app . +COPY --from=build /pinspire/configs configs ENTRYPOINT [ "./app" ] diff --git a/deployments/Dockerfile.messenger b/deployments/Dockerfile.messenger index 6fa332f..cdaec41 100644 --- a/deployments/Dockerfile.messenger +++ b/deployments/Dockerfile.messenger @@ -2,9 +2,9 @@ FROM golang:1.19.13-alpine AS build RUN apk --no-cache add make -WORKDIR /pinspire_messenger +WORKDIR /pinspire -COPY go.mod go.sum /pinspire_messenger/ +COPY go.mod go.sum /pinspire/ RUN go mod download COPY . . @@ -15,6 +15,6 @@ FROM alpine:latest WORKDIR / -COPY --from=build /pinspire_messenger/bin/messenger . +COPY --from=build /pinspire/bin/messenger . ENTRYPOINT [ "./messenger" ] diff --git a/deployments/Dockerfile.realtime b/deployments/Dockerfile.realtime index 7c94295..da5610f 100644 --- a/deployments/Dockerfile.realtime +++ b/deployments/Dockerfile.realtime @@ -2,9 +2,9 @@ FROM golang:1.19.13-alpine AS build RUN apk --no-cache add make -WORKDIR /pinspire_realtime +WORKDIR /pinspire -COPY go.mod go.sum /pinspire_realtime/ +COPY go.mod go.sum /pinspire/ RUN go mod download COPY . . @@ -15,6 +15,6 @@ FROM alpine:latest WORKDIR / -COPY --from=build /pinspire_realtime/bin/realtime . +COPY --from=build /pinspire/bin/realtime . ENTRYPOINT [ "./realtime" ] diff --git a/deployments/compose.prod.yml b/deployments/compose.prod.yml new file mode 100644 index 0000000..5156d5d --- /dev/null +++ b/deployments/compose.prod.yml @@ -0,0 +1,14 @@ +version: '3.8' + +services: + main_service: + image: pinspireapp/main:latest + + auth_service: + image: pinspireapp/auth:latest + + messenger_service: + image: pinspireapp/messenger:latest + + realtime_service: + image: pinspireapp/realtime:latest diff --git a/deployments/docker-compose.yml b/deployments/docker-compose.yml index 094bbab..d36f370 100644 --- a/deployments/docker-compose.yml +++ b/deployments/docker-compose.yml @@ -1,6 +1,5 @@ version: '3.8' - services: postgres: image: postgres:latest @@ -9,6 +8,7 @@ services: - ../.env volumes: - ../db/migrations:/docker-entrypoint-initdb.d + - 'postgres_storage:/var/lib/postgresql/data' ports: - 5432:5432 healthcheck: @@ -19,6 +19,7 @@ services: container_name: pinspireRedis volumes: - ../redis.conf:/usr/local/etc/redis/redis.conf + - 'redis_storage:/data' command: redis-server /usr/local/etc/redis/redis.conf ports: - 6379:6379 @@ -65,7 +66,7 @@ services: redis: condition: 'service_healthy' ports: - - 8086:8086 + - 8186:8086 # - 8101:8085 messenger_service: @@ -81,7 +82,7 @@ services: postgres: condition: 'service_healthy' ports: - - 8096:8096 + - 8196:8096 # - 8102:8095 realtime_service: @@ -96,7 +97,7 @@ services: depends_on: - kafka ports: - - 8091:8091 + - 8191:8091 # - 8103:8090 zookeeper: @@ -171,8 +172,11 @@ services: volumes: + postgres_storage: {} + redis_storage: {} zookeeper_data: driver: local kafka_data: driver: local grafana_storage: {} + From 6c8a215a984a03c080ecdf37e7489420d35afc6d Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Thu, 7 Dec 2023 21:39:15 +0300 Subject: [PATCH 05/21] TP-c01_ci-cd: add workflows description, add configuration file for ansible, add inventory in .gitignore --- .github/workflows/ci.yml | 27 ++++++++++++++++ .github/workflows/deployment.yml | 55 ++++++++++++++++++++++++++++++++ .gitignore | 2 ++ configs/playbook.yml | 16 ++++++++++ 4 files changed, 100 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/deployment.yml create mode 100644 configs/playbook.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..66b52c8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: Start pinspire CI + +on: + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Get repository code + uses: actions/checkout@v4 + - name: Test application + run: go test ./... + lint: + runs-on: ubuntu-latest + steps: + - name: Get repository code + uses: actions/checkout@v4 + - name: Lint application + run: make lint + build: + runs-o: ubuntu-latest + steps: + - name: Get repository code + uses: actions/checkout@v4 + - name: Build application + run: make build_all diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml new file mode 100644 index 0000000..43876cf --- /dev/null +++ b/.github/workflows/deployment.yml @@ -0,0 +1,55 @@ +name: Start Pinspire deployment + +on: + workflow_dispatch: + +jobs: + build_images: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: dev3 + - name: Login to DockerHub Registry + run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin + - name: Build docker images of services + run: | + docker build -t pinspireapp/main:latest -f deployments/Dockerfile.main . & + docker build -t pinspireapp/auth:latest -f deployments/Dockerfile.auth . & + docker build -t pinspireapp/realtime:latest -f deployments/Dockerfile.realtime . & + docker build -t pinspireapp/messenger:latest -f deployments/Dockerfile.messenger . & + for p in $(jobs -p); do wait "$p" || { echo "job $p failed" >&2; exit; }; done + - name: Push docker images + run: | + docker push pinspireapp/main:latest & + docker push pinspireapp/auth:latest & + docker push pinspireapp/realtime:latest & + docker push pinspireapp/messenger:latest & + for p in $(jobs -p); do wait "$p" || { echo "job $p failed" >&2; exit; }; done + + deploy: + runs-on: ubuntu-latest + needs: build_images + steps: + - name: fetch changes + uses: appleboy/ssh-action@master + with: + host: pinspire.online + username: ${{ secrets.REMOTE_USERNAME }} + key: ${{ secrets.PRIVATE_KEY }} + script: | + cd ${{ secrets.PINSPIRE_BACKEND_PATH }} + sudo git switch dev3 + sudo git pull + - name: deploy application + uses: appleboy/ssh-action@master + with: + host: pinspire.online + username: ${{ secrets.REMOTE_USERNAME }} + key: ${{ secrets.PRIVATE_KEY }} + script: | + cd ${{ secrets.PINSPIRE_BACKEND_PATH }}/deployments + sudo docker compose down main_service auth_service realtime_service messenger_service + sudo docker rmi pinspireapp/main:latest pinspireapp/auth:latest pinspireapp/realtime:latest pinspireapp/messenger:latest + docker compose --env-file=../.env -f docker-compose.yml -f compose.prod.yml up -d + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1d94894..e33fae4 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ testdata/ cert/ .env redis.conf +inventory +script* \ No newline at end of file diff --git a/configs/playbook.yml b/configs/playbook.yml new file mode 100644 index 0000000..c3d8bf0 --- /dev/null +++ b/configs/playbook.yml @@ -0,0 +1,16 @@ +- name: "Provide configuration files" + become: yes + hosts: pinspire + tasks: + - name: "Provide .env file" + copy: + src: ../.env + dest: /home/ond_team/go/src/github.com/go-park-mail-ru/ci-cd/.env + - name: "Provide redis config" + copy: + src: ../redis.conf + dest: /home/ond_team/go/src/github.com/go-park-mail-ru/ci-cd/redis.conf + - name: "Provide nginx config" + copy: + src: /etc/nginx/sites-available/pinspire.conf + dest: /etc/nginx/sites-available/pinspire.conf \ No newline at end of file From 7318fe6d77898364d2574bbf0e39d572d19193a0 Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Fri, 8 Dec 2023 13:55:34 +0300 Subject: [PATCH 06/21] TP-c01_ci-cd: add kafka healthcheck --- .github/workflows/deployment.yml | 2 +- deployments/docker-compose.yml | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 43876cf..1928b3a 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -51,5 +51,5 @@ jobs: cd ${{ secrets.PINSPIRE_BACKEND_PATH }}/deployments sudo docker compose down main_service auth_service realtime_service messenger_service sudo docker rmi pinspireapp/main:latest pinspireapp/auth:latest pinspireapp/realtime:latest pinspireapp/messenger:latest - docker compose --env-file=../.env -f docker-compose.yml -f compose.prod.yml up -d + docker compose -f docker-compose.yml -f compose.prod.yml up -d \ No newline at end of file diff --git a/deployments/docker-compose.yml b/deployments/docker-compose.yml index d36f370..1aa64f2 100644 --- a/deployments/docker-compose.yml +++ b/deployments/docker-compose.yml @@ -12,8 +12,12 @@ services: ports: - 5432:5432 healthcheck: - test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}"] - + test: ["CMD", "pg_isready"] + interval: 5s + timeout: 5s + retries: 10 + start_period: 15s + redis: image: redis:latest container_name: pinspireRedis @@ -25,6 +29,10 @@ services: - 6379:6379 healthcheck: test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 5s + retries: 10 + start_period: 15s main_service: build: @@ -95,7 +103,8 @@ services: environment: - KAFKA_BROKER_ADDRESS=kafka depends_on: - - kafka + kafka: + condition: 'service_healthy' ports: - 8191:8091 # - 8103:8090 @@ -122,6 +131,14 @@ services: - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092 - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://:9092 + healthcheck: + test: | + curl localhost:9092 + [ $(echo $?) = '52' ] && exit 0 || exit -1 + interval: 5s + timeout: 5s + retries: 10 + start_period: 15s depends_on: - zookeeper @@ -179,4 +196,3 @@ volumes: kafka_data: driver: local grafana_storage: {} - From eaa7ece7ea3861d95c9fbd5328b75be74b0a7e8c Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Fri, 8 Dec 2023 14:15:45 +0300 Subject: [PATCH 07/21] TP-c01_ci-cd: deleted nginx config from compose.yml, changed triggers, changed ports --- .github/workflows/ci.yml | 15 ++++++++++++--- .github/workflows/deployment.yml | 13 ++++++++++--- cmd/realtime/main.go | 2 ++ configs/config.yml | 2 +- configs/playbook.yml | 4 ---- configs/prometheus.yml | 2 +- deployments/docker-compose.yml | 20 +++++--------------- internal/microservices/realtime/node.go | 1 - internal/pkg/delivery/websocket/websocket.go | 2 +- 9 files changed, 32 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 66b52c8..4a5ad53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,16 @@ name: Start pinspire CI on: - workflow_dispatch: - + workflow_dispatch: {} + push: + branches: + - TP-c01_ci-cd + - dev3 + - dev4 + pull_request: + types: [opened, edited, reopened] + branches: [main, dev4] + jobs: test: runs-on: ubuntu-latest @@ -10,6 +18,7 @@ jobs: - name: Get repository code uses: actions/checkout@v4 - name: Test application + continue-on-error: true run: go test ./... lint: runs-on: ubuntu-latest @@ -19,7 +28,7 @@ jobs: - name: Lint application run: make lint build: - runs-o: ubuntu-latest + runs-on: ubuntu-latest steps: - name: Get repository code uses: actions/checkout@v4 diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 1928b3a..bb54dc3 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -1,7 +1,14 @@ name: Start Pinspire deployment on: - workflow_dispatch: + workflow_dispatch: {} + push: + branches: + - TP-c01_ci-cd + - dev4 + pull_request: + types: [opened, edited, reopened] + branches: [main, dev4] jobs: build_images: @@ -39,7 +46,7 @@ jobs: key: ${{ secrets.PRIVATE_KEY }} script: | cd ${{ secrets.PINSPIRE_BACKEND_PATH }} - sudo git switch dev3 + sudo git switch TP-c01_ci-cd sudo git pull - name: deploy application uses: appleboy/ssh-action@master @@ -51,5 +58,5 @@ jobs: cd ${{ secrets.PINSPIRE_BACKEND_PATH }}/deployments sudo docker compose down main_service auth_service realtime_service messenger_service sudo docker rmi pinspireapp/main:latest pinspireapp/auth:latest pinspireapp/realtime:latest pinspireapp/messenger:latest - docker compose -f docker-compose.yml -f compose.prod.yml up -d + sudo docker compose -f docker-compose.yml -f compose.prod.yml up -d \ No newline at end of file diff --git a/cmd/realtime/main.go b/cmd/realtime/main.go index 1022c65..a01f79f 100644 --- a/cmd/realtime/main.go +++ b/cmd/realtime/main.go @@ -11,11 +11,13 @@ import ( grpcMetrics "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/metrics/grpc" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/middleware/grpc/interceptor" "github.com/go-park-mail-ru/2023_2_OND_team/pkg/logger" + "github.com/joho/godotenv" ) const _address = "0.0.0.0:8090" func main() { + godotenv.Load() log, err := logger.New() if err != nil { fmt.Println(err) diff --git a/configs/config.yml b/configs/config.yml index 4d1fda6..87b2acd 100644 --- a/configs/config.yml +++ b/configs/config.yml @@ -2,6 +2,6 @@ app: server: host: 0.0.0.0 port: 8080 - https: false + https: true certFile: /home/ond_team/cert/fullchain.pem keyFile: /home/ond_team/cert/privkey.pem diff --git a/configs/playbook.yml b/configs/playbook.yml index c3d8bf0..2daa6b2 100644 --- a/configs/playbook.yml +++ b/configs/playbook.yml @@ -10,7 +10,3 @@ copy: src: ../redis.conf dest: /home/ond_team/go/src/github.com/go-park-mail-ru/ci-cd/redis.conf - - name: "Provide nginx config" - copy: - src: /etc/nginx/sites-available/pinspire.conf - dest: /etc/nginx/sites-available/pinspire.conf \ No newline at end of file diff --git a/configs/prometheus.yml b/configs/prometheus.yml index 57406b3..a65d7b8 100644 --- a/configs/prometheus.yml +++ b/configs/prometheus.yml @@ -5,7 +5,7 @@ global: scrape_configs: - job_name: 'api' static_configs: - - targets: ['main_service:8080'] + - targets: ['main_service:8079'] - job_name: 'auth' static_configs: diff --git a/deployments/docker-compose.yml b/deployments/docker-compose.yml index 1aa64f2..44d21c6 100644 --- a/deployments/docker-compose.yml +++ b/deployments/docker-compose.yml @@ -46,6 +46,9 @@ services: - AUTH_SERVICE_HOST=auth_service - MESSENGER_SERVICE_HOST=messenger_service - REALTIME_SERVICE_HOST=realtime_service + volumes: + - '/home/ond_team/cert/fullchain.pem:/home/ond_team/cert/fullchain.pem:ro' + - '/home/ond_team/cert/privkey.pem:/home/ond_team/cert/privkey.pem:ro' depends_on: postgres: condition: 'service_healthy' @@ -56,7 +59,7 @@ services: realtime_service: condition: 'service_started' ports: - - 8100:8080 + - 8079:8080 auth_service: build: @@ -130,7 +133,7 @@ services: - ALLOW_PLAINTEXT_LISTENER=yes - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092 - - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://:9092 + - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 healthcheck: test: | curl localhost:9092 @@ -175,19 +178,6 @@ services: ports: - "9100:9100" - nginx: - image: nginx:latest - container_name: pinspireNginx - volumes: - - '/etc/nginx/sites-available/pinspire.conf:/etc/nginx/conf.d/pinspire.conf:ro' - network_mode: 'host' - depends_on: - main_service: - condition: 'service_started' - realtime_service: - condition: 'service_started' - - volumes: postgres_storage: {} redis_storage: {} diff --git a/internal/microservices/realtime/node.go b/internal/microservices/realtime/node.go index f6f39c7..53d64cc 100644 --- a/internal/microservices/realtime/node.go +++ b/internal/microservices/realtime/node.go @@ -19,7 +19,6 @@ type Node struct { func NewNode() (*Node, error) { node := &Node{} - broker, err := NewKafkaBroker(node, KafkaConfig{ // Addres: []string{"localhost:9092"}, Addres: []string{os.Getenv("KAFKA_BROKER_ADDRESS") + ":" + os.Getenv("KAFKA_BROKER_PORT")}, diff --git a/internal/pkg/delivery/websocket/websocket.go b/internal/pkg/delivery/websocket/websocket.go index c0042de..07635de 100644 --- a/internal/pkg/delivery/websocket/websocket.go +++ b/internal/pkg/delivery/websocket/websocket.go @@ -38,7 +38,7 @@ func SetOriginPatterns(patterns []string) Option { func New(log *log.Logger, mesCase usecase.Usecase, opts ...Option) *HandlerWebSocket { // gRPCConn, err := grpc.Dial("localhost:8090", grpc.WithTransportCredentials(insecure.NewCredentials())) - gRPCConn, err := grpc.Dial(os.Getenv("REALTIME_SERVICE_HOST"+":"+os.Getenv("REALTIME_SERVICE_PORT")), grpc.WithTransportCredentials(insecure.NewCredentials())) + gRPCConn, err := grpc.Dial((os.Getenv("REALTIME_SERVICE_HOST") + ":" + os.Getenv("REALTIME_SERVICE_PORT")), grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Error(fmt.Errorf("grpc dial: %w", err).Error()) } From 8d07119e3b71dec010e1f951a51d7c61f0aefff6 Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Sat, 9 Dec 2023 19:55:59 +0300 Subject: [PATCH 08/21] TP-c01_ci-cd: deleted dev3 from triggers --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a5ad53..69188a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,6 @@ on: push: branches: - TP-c01_ci-cd - - dev3 - dev4 pull_request: types: [opened, edited, reopened] From df49eed9f32451eb0ef66afcfd88e0bdb8232a5f Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Sat, 9 Dec 2023 20:06:28 +0300 Subject: [PATCH 09/21] TP-c01_ci-cd: changed triggers, add step --- .github/workflows/ci.yml | 5 +---- .github/workflows/deployment.yml | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69188a3..e0f2a3f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,10 +2,7 @@ name: Start pinspire CI on: workflow_dispatch: {} - push: - branches: - - TP-c01_ci-cd - - dev4 + push: {} pull_request: types: [opened, edited, reopened] branches: [main, dev4] diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index bb54dc3..9036f2b 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -14,9 +14,8 @@ jobs: build_images: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - with: - ref: dev3 + - name: get repository code + uses: actions/checkout@v4 - name: Login to DockerHub Registry run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin - name: Build docker images of services From 24e85bdd675f95cf78f7dccd750f7c355430fc99 Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Wed, 13 Dec 2023 13:41:41 +0300 Subject: [PATCH 10/21] TP-6ec_easyjson: generated easyjson, changed serialization for user, board, search, subscription --- go.sum | 9 + internal/pkg/delivery/http/v1/board.go | 140 ++-- .../v1/{board_errors.go => errors/board.go} | 12 +- .../pkg/delivery/http/v1/errors/general.go | 111 ++++ .../v1/{search_errors.go => errors/search.go} | 2 +- internal/pkg/delivery/http/v1/profile.go | 3 +- internal/pkg/delivery/http/v1/response.go | 134 +--- internal/pkg/delivery/http/v1/search.go | 5 +- .../pkg/delivery/http/v1/structs/board.go | 71 ++ .../http/v1/structs/board_easyjson.go | 605 ++++++++++++++++++ .../http/v1/{ => structs}/board_validation.go | 2 +- .../pkg/delivery/http/v1/structs/response.go | 17 + .../http/v1/structs/response_easyjson.go | 191 ++++++ .../delivery/http/v1/structs/subscription.go | 17 + .../http/v1/structs/subscription_easyjson.go | 97 +++ internal/pkg/delivery/http/v1/subscription.go | 35 +- internal/pkg/entity/board/board.go | 2 + internal/pkg/entity/board/board_easyjson.go | 163 ++++- .../pkg/entity/comment/comment_easyjson.go | 107 +--- internal/pkg/entity/search/search.go | 5 + internal/pkg/entity/search/search_easyjson.go | 312 +++++++++ internal/pkg/entity/user/user.go | 4 + internal/pkg/entity/user/user_easyjson.go | 233 +++++++ 23 files changed, 1913 insertions(+), 364 deletions(-) rename internal/pkg/delivery/http/v1/{board_errors.go => errors/board.go} (83%) create mode 100644 internal/pkg/delivery/http/v1/errors/general.go rename internal/pkg/delivery/http/v1/{search_errors.go => errors/search.go} (96%) create mode 100644 internal/pkg/delivery/http/v1/structs/board.go create mode 100644 internal/pkg/delivery/http/v1/structs/board_easyjson.go rename internal/pkg/delivery/http/v1/{ => structs}/board_validation.go (98%) create mode 100644 internal/pkg/delivery/http/v1/structs/response.go create mode 100644 internal/pkg/delivery/http/v1/structs/response_easyjson.go create mode 100644 internal/pkg/delivery/http/v1/structs/subscription.go create mode 100644 internal/pkg/delivery/http/v1/structs/subscription_easyjson.go create mode 100644 internal/pkg/entity/search/search_easyjson.go create mode 100644 internal/pkg/entity/user/user_easyjson.go diff --git a/go.sum b/go.sum index c53b878..1ec2c4a 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= @@ -51,6 +53,7 @@ github.com/go-fonts/liberation v0.3.1 h1:9RPT2NhUpxQ7ukUvz3jeUckmN42T9D9TpjtQcqK github.com/go-gorp/gorp v2.0.0+incompatible h1:dIQPsBtl6/H1MjVseWuWPXa7ET4p6Dve4j3Hg+UjqYw= github.com/go-gorp/gorp v2.0.0+incompatible/go.mod h1:7IfkAQnO7jfT/9IQ3R9wL1dFhukN6aQxzKTHnkxzA/E= github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9 h1:NxXI5pTAtpEaU49bpLpQoDsu1zrteW/vxzTz8Cd2UAs= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= @@ -119,6 +122,9 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= @@ -145,6 +151,9 @@ github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvls github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pashagolub/pgxmock/v2 v2.12.0 h1:IVRmQtVFNCoq7NOZ+PdfvB6fwnLJmEuWDhnc3yrDxBs= github.com/pashagolub/pgxmock/v2 v2.12.0/go.mod h1:D3YslkN/nJ4+umVqWmbwfSXugJIjPMChkGBG47OJpNw= diff --git a/internal/pkg/delivery/http/v1/board.go b/internal/pkg/delivery/http/v1/board.go index 910062b..f55db48 100644 --- a/internal/pkg/delivery/http/v1/board.go +++ b/internal/pkg/delivery/http/v1/board.go @@ -2,57 +2,23 @@ package v1 import ( "encoding/json" - "fmt" "net/http" "strconv" "github.com/go-chi/chi/v5" entity "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/entity/board" + "github.com/mailru/easyjson" + errHTTP "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/errors" + "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/structs" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/middleware/auth" log "github.com/go-park-mail-ru/2023_2_OND_team/pkg/logger" ) var TimeFormat = "2006-01-02" -// data for board creation/update -type BoardData struct { - Title *string `json:"title" example:"new board"` - Description *string `json:"description" example:"long desc"` - Public *bool `json:"public" example:"true"` - Tags []string `json:"tags" example:"['blue', 'car']"` -} - -// board view for delivery layer -type CertainBoard struct { - ID int `json:"board_id" example:"22"` - AuthorID int `json:"author_id" example:"22"` - Title string `json:"title" example:"new board"` - Description string `json:"description" example:"long desc"` - CreatedAt string `json:"created_at" example:"07-11-2023"` - PinsNumber int `json:"pins_number" example:"12"` - Pins []string `json:"pins" example:"['/pic1', '/pic2']"` - Tags []string `json:"tags" example:"['love', 'green']"` -} - -type CertainBoardWithUsername struct { - ID int `json:"board_id" example:"22"` - AuthorID int `json:"author_id" example:"22"` - AuthorUsername string `json:"author_username" example:"Bob"` - Title string `json:"title" example:"new board"` - Description string `json:"description" example:"long desc"` - CreatedAt string `json:"created_at" example:"07-11-2023"` - PinsNumber int `json:"pins_number" example:"12"` - Pins []string `json:"pins" example:"['/pic1', '/pic2']"` - Tags []string `json:"tags" example:"['love', 'green']"` -} - -type DeletePinFromBoard struct { - PinID int `json:"pin_id" example:"22"` -} - -func ToCertainBoardFromService(board entity.BoardWithContent) CertainBoard { - return CertainBoard{ +func ToCertainBoardFromService(board entity.BoardWithContent) structs.CertainBoard { + return structs.CertainBoard{ ID: board.BoardInfo.ID, AuthorID: board.BoardInfo.AuthorID, Title: board.BoardInfo.Title, @@ -64,8 +30,8 @@ func ToCertainBoardFromService(board entity.BoardWithContent) CertainBoard { } } -func ToCertainBoardUsernameFromService(board entity.BoardWithContent, username string) CertainBoardWithUsername { - return CertainBoardWithUsername{ +func ToCertainBoardUsernameFromService(board entity.BoardWithContent, username string) structs.CertainBoardWithUsername { + return structs.CertainBoardWithUsername{ ID: board.BoardInfo.ID, AuthorID: board.BoardInfo.AuthorID, AuthorUsername: username, @@ -78,40 +44,20 @@ func ToCertainBoardUsernameFromService(board entity.BoardWithContent, username s } } -func (data *BoardData) Validate() error { - if data.Title == nil || *data.Title == "" { - return ErrInvalidBoardTitle - } - if data.Description == nil { - data.Description = new(string) - *data.Description = "" - } - if data.Public == nil { - return ErrEmptyPubOpt - } - if !isValidBoardTitle(*data.Title) { - return ErrInvalidBoardTitle - } - if err := checkIsValidTagTitles(data.Tags); err != nil { - return fmt.Errorf("%s: %w", err.Error(), ErrInvalidTagTitles) - } - return nil -} - func (h *HandlerHTTP) CreateNewBoard(w http.ResponseWriter, r *http.Request) { logger := h.getRequestLogger(r) if contentType := r.Header.Get("Content-Type"); contentType != ApplicationJson { - code, message := getErrCodeMessage(ErrBadContentType) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadContentType) responseError(w, code, message) return } - var newBoard BoardData - err := json.NewDecoder(r.Body).Decode(&newBoard) + var newBoard structs.BoardData + err := easyjson.UnmarshalFromReader(r.Body, &newBoard) defer r.Body.Close() if err != nil { logger.Info("create board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(ErrBadBody) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadBody) responseError(w, code, message) return } @@ -119,7 +65,7 @@ func (h *HandlerHTTP) CreateNewBoard(w http.ResponseWriter, r *http.Request) { err = newBoard.Validate() if err != nil { logger.Info("create board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(err) + code, message := errHTTP.GetErrCodeMessage(err) responseError(w, code, message) return } @@ -140,7 +86,7 @@ func (h *HandlerHTTP) CreateNewBoard(w http.ResponseWriter, r *http.Request) { if err != nil { logger.Info("create board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(err) + code, message := errHTTP.GetErrCodeMessage(err) responseError(w, code, message) return } @@ -149,7 +95,7 @@ func (h *HandlerHTTP) CreateNewBoard(w http.ResponseWriter, r *http.Request) { if err != nil { logger.Error(err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(ErrInternalError.Error())) + w.Write([]byte(errHTTP.ErrInternalError.Error())) } } @@ -158,8 +104,8 @@ func (h *HandlerHTTP) GetUserBoards(w http.ResponseWriter, r *http.Request) { username := chi.URLParam(r, "username") if !isValidUsername(username) { - logger.Info("update board", log.F{"message", ErrInvalidUsername.Error()}) - code, message := getErrCodeMessage(ErrInvalidUsername) + logger.Info("update board", log.F{"message", errHTTP.ErrInvalidUsername.Error()}) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrInvalidUsername) responseError(w, code, message) return } @@ -167,12 +113,12 @@ func (h *HandlerHTTP) GetUserBoards(w http.ResponseWriter, r *http.Request) { boards, err := h.boardCase.GetBoardsByUsername(r.Context(), username) if err != nil { logger.Info("get user boards", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(err) + code, message := errHTTP.GetErrCodeMessage(err) responseError(w, code, message) return } - userBoards := make([]CertainBoard, 0, len(boards)) + userBoards := make([]structs.CertainBoard, 0, len(boards)) for _, board := range boards { userBoards = append(userBoards, ToCertainBoardFromService(board)) } @@ -180,7 +126,7 @@ func (h *HandlerHTTP) GetUserBoards(w http.ResponseWriter, r *http.Request) { if err != nil { logger.Error(err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(ErrInternalError.Error())) + w.Write([]byte(errHTTP.ErrInternalError.Error())) } } @@ -190,7 +136,7 @@ func (h *HandlerHTTP) GetCertainBoard(w http.ResponseWriter, r *http.Request) { boardID, err := strconv.ParseInt(chi.URLParam(r, "boardID"), 10, 64) if err != nil { logger.Info("get certain board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(ErrBadUrlParam) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadUrlParam) responseError(w, code, message) return } @@ -198,7 +144,7 @@ func (h *HandlerHTTP) GetCertainBoard(w http.ResponseWriter, r *http.Request) { board, username, err := h.boardCase.GetCertainBoard(r.Context(), int(boardID)) if err != nil { logger.Info("get certain board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(err) + code, message := errHTTP.GetErrCodeMessage(err) responseError(w, code, message) return } @@ -207,7 +153,7 @@ func (h *HandlerHTTP) GetCertainBoard(w http.ResponseWriter, r *http.Request) { if err != nil { logger.Error(err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(ErrInternalError.Error())) + w.Write([]byte(errHTTP.ErrInternalError.Error())) } } @@ -217,7 +163,7 @@ func (h *HandlerHTTP) GetBoardInfoForUpdate(w http.ResponseWriter, r *http.Reque boardID, err := strconv.ParseInt(chi.URLParam(r, "boardID"), 10, 64) if err != nil { logger.Info("get certain board info for update", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(ErrBadUrlParam) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadUrlParam) responseError(w, code, message) return } @@ -225,7 +171,7 @@ func (h *HandlerHTTP) GetBoardInfoForUpdate(w http.ResponseWriter, r *http.Reque board, tagTitles, err := h.boardCase.GetBoardInfoForUpdate(r.Context(), int(boardID)) if err != nil { logger.Info("get certain board info for update", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(err) + code, message := errHTTP.GetErrCodeMessage(err) responseError(w, code, message) return } @@ -234,14 +180,14 @@ func (h *HandlerHTTP) GetBoardInfoForUpdate(w http.ResponseWriter, r *http.Reque if err != nil { logger.Error(err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(ErrInternalError.Error())) + w.Write([]byte(errHTTP.ErrInternalError.Error())) } } func (h *HandlerHTTP) UpdateBoardInfo(w http.ResponseWriter, r *http.Request) { logger := h.getRequestLogger(r) if contentType := r.Header.Get("Content-Type"); contentType != ApplicationJson { - code, message := getErrCodeMessage(ErrBadContentType) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadContentType) responseError(w, code, message) return } @@ -249,17 +195,17 @@ func (h *HandlerHTTP) UpdateBoardInfo(w http.ResponseWriter, r *http.Request) { boardID, err := strconv.ParseInt(chi.URLParam(r, "boardID"), 10, 64) if err != nil { logger.Info("update certain board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(ErrBadUrlParam) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadUrlParam) responseError(w, code, message) return } - var updatedData BoardData - err = json.NewDecoder(r.Body).Decode(&updatedData) + var updatedData structs.BoardData + err = easyjson.UnmarshalFromReader(r.Body, &updatedData) defer r.Body.Close() if err != nil { logger.Info("update certain board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(ErrBadBody) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadBody) responseError(w, code, message) return } @@ -267,7 +213,7 @@ func (h *HandlerHTTP) UpdateBoardInfo(w http.ResponseWriter, r *http.Request) { err = updatedData.Validate() if err != nil { logger.Info("update certain board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(err) + code, message := errHTTP.GetErrCodeMessage(err) responseError(w, code, message) return } @@ -286,7 +232,7 @@ func (h *HandlerHTTP) UpdateBoardInfo(w http.ResponseWriter, r *http.Request) { err = h.boardCase.UpdateBoardInfo(r.Context(), updatedBoard, tagTitles) if err != nil { logger.Info("update certain board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(err) + code, message := errHTTP.GetErrCodeMessage(err) responseError(w, code, message) return } @@ -295,7 +241,7 @@ func (h *HandlerHTTP) UpdateBoardInfo(w http.ResponseWriter, r *http.Request) { if err != nil { logger.Error(err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(ErrInternalError.Error())) + w.Write([]byte(errHTTP.ErrInternalError.Error())) } } @@ -305,7 +251,7 @@ func (h *HandlerHTTP) DeleteBoard(w http.ResponseWriter, r *http.Request) { boardID, err := strconv.ParseInt(chi.URLParam(r, "boardID"), 10, 64) if err != nil { logger.Info("update certain board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(ErrBadUrlParam) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadUrlParam) responseError(w, code, message) return } @@ -313,7 +259,7 @@ func (h *HandlerHTTP) DeleteBoard(w http.ResponseWriter, r *http.Request) { err = h.boardCase.DeleteCertainBoard(r.Context(), int(boardID)) if err != nil { logger.Info("update certain board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(err) + code, message := errHTTP.GetErrCodeMessage(err) responseError(w, code, message) return } @@ -322,7 +268,7 @@ func (h *HandlerHTTP) DeleteBoard(w http.ResponseWriter, r *http.Request) { if err != nil { logger.Error(err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(ErrInternalError.Error())) + w.Write([]byte(errHTTP.ErrInternalError.Error())) } } @@ -390,21 +336,21 @@ func (h *HandlerHTTP) DeletePinFromBoard(w http.ResponseWriter, r *http.Request) boardID, err := strconv.ParseInt(chi.URLParam(r, "boardID"), 10, 64) if err != nil { logger.Info("delete pin from board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(ErrBadUrlParam) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadUrlParam) responseError(w, code, message) return } if contentType := r.Header.Get("Content-Type"); contentType != ApplicationJson { - code, message := getErrCodeMessage(ErrBadContentType) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadContentType) responseError(w, code, message) return } - delPinFromBoard := DeletePinFromBoard{} - err = json.NewDecoder(r.Body).Decode(&delPinFromBoard) + delPinFromBoard := structs.DeletePinFromBoard{} + err = easyjson.UnmarshalFromReader(r.Body, &delPinFromBoard) if err != nil { - code, message := getErrCodeMessage(ErrBadBody) + code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadBody) responseError(w, code, message) return } @@ -413,7 +359,7 @@ func (h *HandlerHTTP) DeletePinFromBoard(w http.ResponseWriter, r *http.Request) err = h.boardCase.DeletePinFromBoard(r.Context(), int(boardID), delPinFromBoard.PinID) if err != nil { logger.Info("delete pin from board", log.F{"message", err.Error()}) - code, message := getErrCodeMessage(err) + code, message := errHTTP.GetErrCodeMessage(err) responseError(w, code, message) return } @@ -422,6 +368,6 @@ func (h *HandlerHTTP) DeletePinFromBoard(w http.ResponseWriter, r *http.Request) if err != nil { logger.Error(err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(ErrInternalError.Error())) + w.Write([]byte(errHTTP.ErrInternalError.Error())) } } diff --git a/internal/pkg/delivery/http/v1/board_errors.go b/internal/pkg/delivery/http/v1/errors/board.go similarity index 83% rename from internal/pkg/delivery/http/v1/board_errors.go rename to internal/pkg/delivery/http/v1/errors/board.go index ab31833..0d2106c 100644 --- a/internal/pkg/delivery/http/v1/board_errors.go +++ b/internal/pkg/delivery/http/v1/errors/board.go @@ -1,4 +1,4 @@ -package v1 +package errors import ( "errors" @@ -16,8 +16,8 @@ var ( ) var ( - wrappedErrors = map[error]string{ErrInvalidTagTitles: "bad_Tagtitles"} - errCodeCompability = map[error]string{ + WrappedErrors = map[error]string{ErrInvalidTagTitles: "bad_Tagtitles"} + ErrCodeCompability = map[error]string{ ErrInvalidBoardTitle: "bad_boardTitle", ErrEmptyTitle: "empty_boardTitle", ErrEmptyPubOpt: "bad_pubOpt", @@ -29,7 +29,7 @@ var ( } ) -func getErrCodeMessage(err error) (string, string) { +func GetErrCodeMessage(err error) (string, string) { var ( code string general, specific bool @@ -40,9 +40,9 @@ func getErrCodeMessage(err error) (string, string) { return code, err.Error() } - code, specific = errCodeCompability[err] + code, specific = ErrCodeCompability[err] if !specific { - for wrappedErr, code_ := range wrappedErrors { + for wrappedErr, code_ := range WrappedErrors { if errors.Is(err, wrappedErr) { specific = true code = code_ diff --git a/internal/pkg/delivery/http/v1/errors/general.go b/internal/pkg/delivery/http/v1/errors/general.go new file mode 100644 index 0000000..d60b0c3 --- /dev/null +++ b/internal/pkg/delivery/http/v1/errors/general.go @@ -0,0 +1,111 @@ +package errors + +import ( + "errors" + "fmt" + "net/http" + + errPkg "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/errors" +) + +// for backward compatibility - begin +var ( + ErrBadBody = errors.New("can't parse body, JSON with correct data types is expected") + ErrBadUrlParam = errors.New("bad URL param has been provided") + ErrBadQueryParam = errors.New("invalid query parameters have been provided") + ErrInternalError = errors.New("internal server error occured") + ErrBadContentType = errors.New("application/json is expected") +) + +var ( + generalErrCodeCompability = map[error]string{ + ErrBadBody: "bad_body", + ErrBadQueryParam: "bad_queryParams", + ErrInternalError: "internal_error", + ErrBadContentType: "bad_contentType", + ErrBadUrlParam: "bad_urlParam", + } +) + +// for backward compatibility - end + +type ErrInvalidBody struct{} + +func (e *ErrInvalidBody) Error() string { + return "invalid body" +} + +func (e *ErrInvalidBody) Type() errPkg.Type { + return errPkg.ErrInvalidInput +} + +type ErrInvalidQueryParam struct { + Params map[string]string +} + +func (e *ErrInvalidQueryParam) Error() string { + return fmt.Sprintf("invalid query params: %v", e.Params) +} + +func (e *ErrInvalidQueryParam) Type() errPkg.Type { + return errPkg.ErrInvalidInput +} + +type ErrInvalidContentType struct { + PreferredType string +} + +func (e *ErrInvalidContentType) Error() string { + return fmt.Sprintf("invalid content type, should be %s", e.PreferredType) +} + +func (e *ErrInvalidContentType) Type() errPkg.Type { + return errPkg.ErrInvalidInput +} + +type ErrInvalidUrlParams struct { + Params map[string]string +} + +func (e *ErrInvalidUrlParams) Error() string { + return fmt.Sprintf("invalid URL params: %v", e.Params) +} + +func (e *ErrInvalidUrlParams) Type() errPkg.Type { + return errPkg.ErrInvalidInput +} + +type ErrMissingBodyParams struct { + Params []string +} + +func (e *ErrMissingBodyParams) Error() string { + return fmt.Sprintf("missing body params: %v", e.Params) +} + +func (e *ErrMissingBodyParams) Type() errPkg.Type { + return errPkg.ErrInvalidInput +} + +func GetCodeStatusHttp(err error) (ErrCode string, httpStatus int) { + + var declaredErr errPkg.DeclaredError + if errors.As(err, &declaredErr) { + switch declaredErr.Type() { + case errPkg.ErrInvalidInput: + return "bad_input", http.StatusBadRequest + case errPkg.ErrNotFound: + return "not_found", http.StatusNotFound + case errPkg.ErrAlreadyExists: + return "already_exists", http.StatusConflict + case errPkg.ErrNoAuth: + return "no_auth", http.StatusUnauthorized + case errPkg.ErrNoAccess: + return "no_access", http.StatusForbidden + case errPkg.ErrTimeout: + return "timeout", http.StatusRequestTimeout + } + } + + return "internal_error", http.StatusInternalServerError +} diff --git a/internal/pkg/delivery/http/v1/search_errors.go b/internal/pkg/delivery/http/v1/errors/search.go similarity index 96% rename from internal/pkg/delivery/http/v1/search_errors.go rename to internal/pkg/delivery/http/v1/errors/search.go index 1fb9f00..74abdec 100644 --- a/internal/pkg/delivery/http/v1/search_errors.go +++ b/internal/pkg/delivery/http/v1/errors/search.go @@ -1,4 +1,4 @@ -package v1 +package errors import errPkg "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/errors" diff --git a/internal/pkg/delivery/http/v1/profile.go b/internal/pkg/delivery/http/v1/profile.go index b03ed6f..66ab2ab 100644 --- a/internal/pkg/delivery/http/v1/profile.go +++ b/internal/pkg/delivery/http/v1/profile.go @@ -7,6 +7,7 @@ import ( "strconv" "github.com/go-chi/chi/v5" + errHTTP "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/errors" userEntity "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/entity/user" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/middleware/auth" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/usecase/user" @@ -57,7 +58,7 @@ func (h *HandlerHTTP) GetUserInfo(w http.ResponseWriter, r *http.Request) { userIdParam := chi.URLParam(r, "userID") userID, err := strconv.ParseInt(userIdParam, 10, 64) if err != nil { - h.responseErr(w, r, &ErrInvalidUrlParams{map[string]string{"userID": userIdParam}}) + h.responseErr(w, r, &errHTTP.ErrInvalidUrlParams{Params: map[string]string{"userID": userIdParam}}) return } diff --git a/internal/pkg/delivery/http/v1/response.go b/internal/pkg/delivery/http/v1/response.go index 98ab544..7b77059 100644 --- a/internal/pkg/delivery/http/v1/response.go +++ b/internal/pkg/delivery/http/v1/response.go @@ -1,140 +1,26 @@ package v1 import ( - "encoding/json" - "errors" "fmt" "net/http" - errPkg "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/errors" + errHTTP "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/errors" + "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/structs" "github.com/go-park-mail-ru/2023_2_OND_team/pkg/logger" + "github.com/mailru/easyjson" ) -// for backward compatibility - begin -var ( - ErrBadBody = errors.New("can't parse body, JSON with correct data types is expected") - ErrBadUrlParam = errors.New("bad URL param has been provided") - ErrBadQueryParam = errors.New("invalid query parameters have been provided") - ErrInternalError = errors.New("internal server error occured") - ErrBadContentType = errors.New("application/json is expected") -) - -var ( - generalErrCodeCompability = map[error]string{ - ErrBadBody: "bad_body", - ErrBadQueryParam: "bad_queryParams", - ErrInternalError: "internal_error", - ErrBadContentType: "bad_contentType", - ErrBadUrlParam: "bad_urlParam", - } -) - -// for backward compatibility - end - -type ErrInvalidBody struct{} - -func (e *ErrInvalidBody) Error() string { - return "invalid body" -} - -func (e *ErrInvalidBody) Type() errPkg.Type { - return errPkg.ErrInvalidInput -} - -type ErrInvalidQueryParam struct { - params map[string]string -} - -func (e *ErrInvalidQueryParam) Error() string { - return fmt.Sprintf("invalid query params: %v", e.params) -} - -func (e *ErrInvalidQueryParam) Type() errPkg.Type { - return errPkg.ErrInvalidInput -} - -type ErrInvalidContentType struct { - preferredType string -} - -func (e *ErrInvalidContentType) Error() string { - return fmt.Sprintf("invalid content type, should be %s", e.preferredType) -} - -func (e *ErrInvalidContentType) Type() errPkg.Type { - return errPkg.ErrInvalidInput -} - -type ErrInvalidUrlParams struct { - params map[string]string -} - -func (e *ErrInvalidUrlParams) Error() string { - return fmt.Sprintf("invalid URL params: %v", e.params) -} - -func (e *ErrInvalidUrlParams) Type() errPkg.Type { - return errPkg.ErrInvalidInput -} - -type ErrMissingBodyParams struct { - params []string -} - -func (e *ErrMissingBodyParams) Error() string { - return fmt.Sprintf("missing body params: %v", e.params) -} - -func (e *ErrMissingBodyParams) Type() errPkg.Type { - return errPkg.ErrInvalidInput -} - -func getCodeStatusHttp(err error) (ErrCode string, httpStatus int) { - - var declaredErr errPkg.DeclaredError - if errors.As(err, &declaredErr) { - switch declaredErr.Type() { - case errPkg.ErrInvalidInput: - return "bad_input", http.StatusBadRequest - case errPkg.ErrNotFound: - return "not_found", http.StatusNotFound - case errPkg.ErrAlreadyExists: - return "already_exists", http.StatusConflict - case errPkg.ErrNoAuth: - return "no_auth", http.StatusUnauthorized - case errPkg.ErrNoAccess: - return "no_access", http.StatusForbidden - case errPkg.ErrTimeout: - return "timeout", http.StatusRequestTimeout - } - } - - return "internal_error", http.StatusInternalServerError -} - -type JsonResponse struct { - Status string `json:"status" example:"ok"` - Message string `json:"message" example:"Response message"` - Body interface{} `json:"body" extensions:"x-omitempty"` -} // @name JsonResponse - -type JsonErrResponse struct { - Status string `json:"status" example:"error"` - Message string `json:"message" example:"Error description"` - Code string `json:"code"` -} // @name JsonErrResponse - func SetContentTypeJSON(w http.ResponseWriter) { w.Header().Set("Content-Type", "application/json") } func responseOk(statusCode int, w http.ResponseWriter, message string, body any) error { - res := JsonResponse{ + res := structs.JsonResponse{ Status: "ok", Message: message, Body: body, } - resBytes, err := json.Marshal(res) + resBytes, err := easyjson.Marshal(res) if err != nil { w.WriteHeader(http.StatusInternalServerError) return fmt.Errorf("responseOk: %w", err) @@ -146,12 +32,12 @@ func responseOk(statusCode int, w http.ResponseWriter, message string, body any) } func responseError(w http.ResponseWriter, code, message string) error { - res := JsonErrResponse{ + res := structs.JsonErrResponse{ Status: "error", Message: message, Code: code, } - resBytes, err := json.Marshal(res) + resBytes, err := easyjson.Marshal(res) if err != nil { return fmt.Errorf("responseError: %w", err) } @@ -162,7 +48,7 @@ func responseError(w http.ResponseWriter, code, message string) error { func (h *HandlerHTTP) responseErr(w http.ResponseWriter, r *http.Request, err error) error { log := logger.GetLoggerFromCtx(r.Context()) - code, status := getCodeStatusHttp(err) + code, status := errHTTP.GetCodeStatusHttp(err) var msg string if status == http.StatusInternalServerError { log.Warnf("unexpected application error: %s", err.Error()) @@ -171,12 +57,12 @@ func (h *HandlerHTTP) responseErr(w http.ResponseWriter, r *http.Request, err er msg = err.Error() } - res := JsonErrResponse{ + res := structs.JsonErrResponse{ Status: "error", Message: msg, Code: code, } - resBytes, err := json.Marshal(res) + resBytes, err := easyjson.Marshal(res) if err != nil { return fmt.Errorf("responseError: %w", err) } diff --git a/internal/pkg/delivery/http/v1/search.go b/internal/pkg/delivery/http/v1/search.go index f798d36..4ec1e79 100644 --- a/internal/pkg/delivery/http/v1/search.go +++ b/internal/pkg/delivery/http/v1/search.go @@ -4,6 +4,7 @@ import ( "net/http" "strconv" + errHTTP "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/errors" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/entity/search" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/middleware/auth" ) @@ -89,7 +90,7 @@ func GetSearchOpts(r *http.Request, sortOpts []string, defaultSortOpt string) (* } if len(invalidParams) > 0 { - return nil, &ErrInvalidQueryParam{params: invalidParams} + return nil, &errHTTP.ErrInvalidQueryParam{Params: invalidParams} } return opts, nil @@ -114,7 +115,7 @@ func GetGeneralOpts(r *http.Request, invalidParams map[string]string) (*search.G opts.Template = template } } else { - return nil, &ErrNoData{} + return nil, &errHTTP.ErrNoData{} } if sortOrder := r.URL.Query().Get("order"); sortOrder != "" { diff --git a/internal/pkg/delivery/http/v1/structs/board.go b/internal/pkg/delivery/http/v1/structs/board.go new file mode 100644 index 0000000..e6aa540 --- /dev/null +++ b/internal/pkg/delivery/http/v1/structs/board.go @@ -0,0 +1,71 @@ +package structs + +import ( + "fmt" + + errHTTP "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/errors" +) + +//go:generate easyjson board.go + +// data for board creation/update +// +//easyjson:json +type BoardData struct { + Title *string `json:"title" example:"new board"` + Description *string `json:"description" example:"long desc"` + Public *bool `json:"public" example:"true"` + Tags []string `json:"tags" example:"['blue', 'car']"` +} + +// board view for delivery layer +// +//easyjson:json +type CertainBoard struct { + ID int `json:"board_id" example:"22"` + AuthorID int `json:"author_id" example:"22"` + Title string `json:"title" example:"new board"` + Description string `json:"description" example:"long desc"` + CreatedAt string `json:"created_at" example:"07-11-2023"` + PinsNumber int `json:"pins_number" example:"12"` + Pins []string `json:"pins" example:"['/pic1', '/pic2']"` + Tags []string `json:"tags" example:"['love', 'green']"` +} + +//easyjson:json +type CertainBoardWithUsername struct { + ID int `json:"board_id" example:"22"` + AuthorID int `json:"author_id" example:"22"` + AuthorUsername string `json:"author_username" example:"Bob"` + Title string `json:"title" example:"new board"` + Description string `json:"description" example:"long desc"` + CreatedAt string `json:"created_at" example:"07-11-2023"` + PinsNumber int `json:"pins_number" example:"12"` + Pins []string `json:"pins" example:"['/pic1', '/pic2']"` + Tags []string `json:"tags" example:"['love', 'green']"` +} + +//easyjson:json +type DeletePinFromBoard struct { + PinID int `json:"pin_id" example:"22"` +} + +func (data *BoardData) Validate() error { + if data.Title == nil || *data.Title == "" { + return errHTTP.ErrInvalidBoardTitle + } + if data.Description == nil { + data.Description = new(string) + *data.Description = "" + } + if data.Public == nil { + return errHTTP.ErrEmptyPubOpt + } + if !isValidBoardTitle(*data.Title) { + return errHTTP.ErrInvalidBoardTitle + } + if err := checkIsValidTagTitles(data.Tags); err != nil { + return fmt.Errorf("%s: %w", err.Error(), errHTTP.ErrInvalidTagTitles) + } + return nil +} diff --git a/internal/pkg/delivery/http/v1/structs/board_easyjson.go b/internal/pkg/delivery/http/v1/structs/board_easyjson.go new file mode 100644 index 0000000..b847d66 --- /dev/null +++ b/internal/pkg/delivery/http/v1/structs/board_easyjson.go @@ -0,0 +1,605 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package structs + +import ( + json "encoding/json" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(in *jlexer.Lexer, out *DeletePinFromBoard) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "pin_id": + out.PinID = int(in.Int()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(out *jwriter.Writer, in DeletePinFromBoard) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"pin_id\":" + out.RawString(prefix[1:]) + out.Int(int(in.PinID)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v DeletePinFromBoard) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v DeletePinFromBoard) MarshalEasyJSON(w *jwriter.Writer) { + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *DeletePinFromBoard) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *DeletePinFromBoard) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(l, v) +} +func easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(in *jlexer.Lexer, out *CertainBoardWithUsername) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "board_id": + out.ID = int(in.Int()) + case "author_id": + out.AuthorID = int(in.Int()) + case "author_username": + out.AuthorUsername = string(in.String()) + case "title": + out.Title = string(in.String()) + case "description": + out.Description = string(in.String()) + case "created_at": + out.CreatedAt = string(in.String()) + case "pins_number": + out.PinsNumber = int(in.Int()) + case "pins": + if in.IsNull() { + in.Skip() + out.Pins = nil + } else { + in.Delim('[') + if out.Pins == nil { + if !in.IsDelim(']') { + out.Pins = make([]string, 0, 4) + } else { + out.Pins = []string{} + } + } else { + out.Pins = (out.Pins)[:0] + } + for !in.IsDelim(']') { + var v1 string + v1 = string(in.String()) + out.Pins = append(out.Pins, v1) + in.WantComma() + } + in.Delim(']') + } + case "tags": + if in.IsNull() { + in.Skip() + out.Tags = nil + } else { + in.Delim('[') + if out.Tags == nil { + if !in.IsDelim(']') { + out.Tags = make([]string, 0, 4) + } else { + out.Tags = []string{} + } + } else { + out.Tags = (out.Tags)[:0] + } + for !in.IsDelim(']') { + var v2 string + v2 = string(in.String()) + out.Tags = append(out.Tags, v2) + in.WantComma() + } + in.Delim(']') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(out *jwriter.Writer, in CertainBoardWithUsername) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"board_id\":" + out.RawString(prefix[1:]) + out.Int(int(in.ID)) + } + { + const prefix string = ",\"author_id\":" + out.RawString(prefix) + out.Int(int(in.AuthorID)) + } + { + const prefix string = ",\"author_username\":" + out.RawString(prefix) + out.String(string(in.AuthorUsername)) + } + { + const prefix string = ",\"title\":" + out.RawString(prefix) + out.String(string(in.Title)) + } + { + const prefix string = ",\"description\":" + out.RawString(prefix) + out.String(string(in.Description)) + } + { + const prefix string = ",\"created_at\":" + out.RawString(prefix) + out.String(string(in.CreatedAt)) + } + { + const prefix string = ",\"pins_number\":" + out.RawString(prefix) + out.Int(int(in.PinsNumber)) + } + { + const prefix string = ",\"pins\":" + out.RawString(prefix) + if in.Pins == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v3, v4 := range in.Pins { + if v3 > 0 { + out.RawByte(',') + } + out.String(string(v4)) + } + out.RawByte(']') + } + } + { + const prefix string = ",\"tags\":" + out.RawString(prefix) + if in.Tags == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v5, v6 := range in.Tags { + if v5 > 0 { + out.RawByte(',') + } + out.String(string(v6)) + } + out.RawByte(']') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v CertainBoardWithUsername) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v CertainBoardWithUsername) MarshalEasyJSON(w *jwriter.Writer) { + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *CertainBoardWithUsername) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *CertainBoardWithUsername) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(l, v) +} +func easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs2(in *jlexer.Lexer, out *CertainBoard) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "board_id": + out.ID = int(in.Int()) + case "author_id": + out.AuthorID = int(in.Int()) + case "title": + out.Title = string(in.String()) + case "description": + out.Description = string(in.String()) + case "created_at": + out.CreatedAt = string(in.String()) + case "pins_number": + out.PinsNumber = int(in.Int()) + case "pins": + if in.IsNull() { + in.Skip() + out.Pins = nil + } else { + in.Delim('[') + if out.Pins == nil { + if !in.IsDelim(']') { + out.Pins = make([]string, 0, 4) + } else { + out.Pins = []string{} + } + } else { + out.Pins = (out.Pins)[:0] + } + for !in.IsDelim(']') { + var v7 string + v7 = string(in.String()) + out.Pins = append(out.Pins, v7) + in.WantComma() + } + in.Delim(']') + } + case "tags": + if in.IsNull() { + in.Skip() + out.Tags = nil + } else { + in.Delim('[') + if out.Tags == nil { + if !in.IsDelim(']') { + out.Tags = make([]string, 0, 4) + } else { + out.Tags = []string{} + } + } else { + out.Tags = (out.Tags)[:0] + } + for !in.IsDelim(']') { + var v8 string + v8 = string(in.String()) + out.Tags = append(out.Tags, v8) + in.WantComma() + } + in.Delim(']') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs2(out *jwriter.Writer, in CertainBoard) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"board_id\":" + out.RawString(prefix[1:]) + out.Int(int(in.ID)) + } + { + const prefix string = ",\"author_id\":" + out.RawString(prefix) + out.Int(int(in.AuthorID)) + } + { + const prefix string = ",\"title\":" + out.RawString(prefix) + out.String(string(in.Title)) + } + { + const prefix string = ",\"description\":" + out.RawString(prefix) + out.String(string(in.Description)) + } + { + const prefix string = ",\"created_at\":" + out.RawString(prefix) + out.String(string(in.CreatedAt)) + } + { + const prefix string = ",\"pins_number\":" + out.RawString(prefix) + out.Int(int(in.PinsNumber)) + } + { + const prefix string = ",\"pins\":" + out.RawString(prefix) + if in.Pins == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v9, v10 := range in.Pins { + if v9 > 0 { + out.RawByte(',') + } + out.String(string(v10)) + } + out.RawByte(']') + } + } + { + const prefix string = ",\"tags\":" + out.RawString(prefix) + if in.Tags == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v11, v12 := range in.Tags { + if v11 > 0 { + out.RawByte(',') + } + out.String(string(v12)) + } + out.RawByte(']') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v CertainBoard) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs2(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v CertainBoard) MarshalEasyJSON(w *jwriter.Writer) { + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs2(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *CertainBoard) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs2(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *CertainBoard) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs2(l, v) +} +func easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs3(in *jlexer.Lexer, out *BoardData) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "title": + if in.IsNull() { + in.Skip() + out.Title = nil + } else { + if out.Title == nil { + out.Title = new(string) + } + *out.Title = string(in.String()) + } + case "description": + if in.IsNull() { + in.Skip() + out.Description = nil + } else { + if out.Description == nil { + out.Description = new(string) + } + *out.Description = string(in.String()) + } + case "public": + if in.IsNull() { + in.Skip() + out.Public = nil + } else { + if out.Public == nil { + out.Public = new(bool) + } + *out.Public = bool(in.Bool()) + } + case "tags": + if in.IsNull() { + in.Skip() + out.Tags = nil + } else { + in.Delim('[') + if out.Tags == nil { + if !in.IsDelim(']') { + out.Tags = make([]string, 0, 4) + } else { + out.Tags = []string{} + } + } else { + out.Tags = (out.Tags)[:0] + } + for !in.IsDelim(']') { + var v13 string + v13 = string(in.String()) + out.Tags = append(out.Tags, v13) + in.WantComma() + } + in.Delim(']') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs3(out *jwriter.Writer, in BoardData) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"title\":" + out.RawString(prefix[1:]) + if in.Title == nil { + out.RawString("null") + } else { + out.String(string(*in.Title)) + } + } + { + const prefix string = ",\"description\":" + out.RawString(prefix) + if in.Description == nil { + out.RawString("null") + } else { + out.String(string(*in.Description)) + } + } + { + const prefix string = ",\"public\":" + out.RawString(prefix) + if in.Public == nil { + out.RawString("null") + } else { + out.Bool(bool(*in.Public)) + } + } + { + const prefix string = ",\"tags\":" + out.RawString(prefix) + if in.Tags == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v14, v15 := range in.Tags { + if v14 > 0 { + out.RawByte(',') + } + out.String(string(v15)) + } + out.RawByte(']') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v BoardData) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs3(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v BoardData) MarshalEasyJSON(w *jwriter.Writer) { + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs3(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *BoardData) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs3(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *BoardData) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs3(l, v) +} diff --git a/internal/pkg/delivery/http/v1/board_validation.go b/internal/pkg/delivery/http/v1/structs/board_validation.go similarity index 98% rename from internal/pkg/delivery/http/v1/board_validation.go rename to internal/pkg/delivery/http/v1/structs/board_validation.go index 0cabf18..6181434 100644 --- a/internal/pkg/delivery/http/v1/board_validation.go +++ b/internal/pkg/delivery/http/v1/structs/board_validation.go @@ -1,4 +1,4 @@ -package v1 +package structs import ( "fmt" diff --git a/internal/pkg/delivery/http/v1/structs/response.go b/internal/pkg/delivery/http/v1/structs/response.go new file mode 100644 index 0000000..e922b82 --- /dev/null +++ b/internal/pkg/delivery/http/v1/structs/response.go @@ -0,0 +1,17 @@ +package structs + +//go:generate easyjson subscription.go + +//easyjson:json +type JsonResponse struct { + Status string `json:"status" example:"ok"` + Message string `json:"message" example:"Response message"` + Body interface{} `json:"body" extensions:"x-omitempty"` +} // @name JsonResponse + +//easyjson:json +type JsonErrResponse struct { + Status string `json:"status" example:"error"` + Message string `json:"message" example:"Error description"` + Code string `json:"code"` +} // @name JsonErrResponse diff --git a/internal/pkg/delivery/http/v1/structs/response_easyjson.go b/internal/pkg/delivery/http/v1/structs/response_easyjson.go new file mode 100644 index 0000000..91dfdd8 --- /dev/null +++ b/internal/pkg/delivery/http/v1/structs/response_easyjson.go @@ -0,0 +1,191 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package structs + +import ( + json "encoding/json" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjson6ff3ac1dDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(in *jlexer.Lexer, out *JsonResponse) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "status": + out.Status = string(in.String()) + case "message": + out.Message = string(in.String()) + case "body": + if m, ok := out.Body.(easyjson.Unmarshaler); ok { + m.UnmarshalEasyJSON(in) + } else if m, ok := out.Body.(json.Unmarshaler); ok { + _ = m.UnmarshalJSON(in.Raw()) + } else { + out.Body = in.Interface() + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson6ff3ac1dEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(out *jwriter.Writer, in JsonResponse) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"status\":" + out.RawString(prefix[1:]) + out.String(string(in.Status)) + } + { + const prefix string = ",\"message\":" + out.RawString(prefix) + out.String(string(in.Message)) + } + { + const prefix string = ",\"body\":" + out.RawString(prefix) + if m, ok := in.Body.(easyjson.Marshaler); ok { + m.MarshalEasyJSON(out) + } else if m, ok := in.Body.(json.Marshaler); ok { + out.Raw(m.MarshalJSON()) + } else { + out.Raw(json.Marshal(in.Body)) + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v JsonResponse) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson6ff3ac1dEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v JsonResponse) MarshalEasyJSON(w *jwriter.Writer) { + easyjson6ff3ac1dEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *JsonResponse) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson6ff3ac1dDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *JsonResponse) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson6ff3ac1dDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(l, v) +} +func easyjson6ff3ac1dDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(in *jlexer.Lexer, out *JsonErrResponse) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "status": + out.Status = string(in.String()) + case "message": + out.Message = string(in.String()) + case "code": + out.Code = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson6ff3ac1dEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(out *jwriter.Writer, in JsonErrResponse) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"status\":" + out.RawString(prefix[1:]) + out.String(string(in.Status)) + } + { + const prefix string = ",\"message\":" + out.RawString(prefix) + out.String(string(in.Message)) + } + { + const prefix string = ",\"code\":" + out.RawString(prefix) + out.String(string(in.Code)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v JsonErrResponse) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson6ff3ac1dEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v JsonErrResponse) MarshalEasyJSON(w *jwriter.Writer) { + easyjson6ff3ac1dEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *JsonErrResponse) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson6ff3ac1dDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *JsonErrResponse) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson6ff3ac1dDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(l, v) +} diff --git a/internal/pkg/delivery/http/v1/structs/subscription.go b/internal/pkg/delivery/http/v1/structs/subscription.go new file mode 100644 index 0000000..73bee4d --- /dev/null +++ b/internal/pkg/delivery/http/v1/structs/subscription.go @@ -0,0 +1,17 @@ +package structs + +import errHTTP "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/errors" + +//go:generate easyjson subscription.go + +//easyjson:json +type SubscriptionAction struct { + To *int `json:"to" example:"2"` +} + +func (s *SubscriptionAction) Validate() error { + if s.To == nil { + return &errHTTP.ErrMissingBodyParams{Params: []string{"to"}} + } + return nil +} diff --git a/internal/pkg/delivery/http/v1/structs/subscription_easyjson.go b/internal/pkg/delivery/http/v1/structs/subscription_easyjson.go new file mode 100644 index 0000000..b1e0fd9 --- /dev/null +++ b/internal/pkg/delivery/http/v1/structs/subscription_easyjson.go @@ -0,0 +1,97 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package structs + +import ( + json "encoding/json" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjsonFfbd3743DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(in *jlexer.Lexer, out *SubscriptionAction) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "to": + if in.IsNull() { + in.Skip() + out.To = nil + } else { + if out.To == nil { + out.To = new(int) + } + *out.To = int(in.Int()) + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonFfbd3743EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(out *jwriter.Writer, in SubscriptionAction) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"to\":" + out.RawString(prefix[1:]) + if in.To == nil { + out.RawString("null") + } else { + out.Int(int(*in.To)) + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v SubscriptionAction) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonFfbd3743EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v SubscriptionAction) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonFfbd3743EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *SubscriptionAction) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonFfbd3743DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *SubscriptionAction) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonFfbd3743DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(l, v) +} diff --git a/internal/pkg/delivery/http/v1/subscription.go b/internal/pkg/delivery/http/v1/subscription.go index 4614476..7444bdf 100644 --- a/internal/pkg/delivery/http/v1/subscription.go +++ b/internal/pkg/delivery/http/v1/subscription.go @@ -1,12 +1,15 @@ package v1 import ( - "encoding/json" "net/http" "strconv" + errHTTP "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/errors" + + "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/structs" userEntity "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/entity/user" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/middleware/auth" + "github.com/mailru/easyjson" ) var ( @@ -17,26 +20,16 @@ var ( maxCount = 50 ) -type SubscriptionAction struct { - To *int `json:"to" example:"2"` -} - -func (s *SubscriptionAction) Validate() error { - if s.To == nil { - return &ErrMissingBodyParams{[]string{"to"}} - } - return nil -} - func (h *HandlerHTTP) Subscribe(w http.ResponseWriter, r *http.Request) { if contentType := r.Header.Get("Content-Type"); contentType != ApplicationJson { - h.responseErr(w, r, &ErrInvalidContentType{preferredType: ApplicationJson}) + h.responseErr(w, r, &errHTTP.ErrInvalidContentType{PreferredType: ApplicationJson}) return } - sub := SubscriptionAction{} - if err := json.NewDecoder(r.Body).Decode(&sub); err != nil { - h.responseErr(w, r, &ErrInvalidBody{}) + sub := structs.SubscriptionAction{} + + if err := easyjson.UnmarshalFromReader(r.Body, &sub); err != nil { + h.responseErr(w, r, &errHTTP.ErrInvalidBody{}) return } defer r.Body.Close() @@ -56,13 +49,13 @@ func (h *HandlerHTTP) Subscribe(w http.ResponseWriter, r *http.Request) { func (h *HandlerHTTP) Unsubscribe(w http.ResponseWriter, r *http.Request) { if contentType := r.Header.Get("Content-Type"); contentType != ApplicationJson { - h.responseErr(w, r, &ErrInvalidContentType{preferredType: ApplicationJson}) + h.responseErr(w, r, &errHTTP.ErrInvalidContentType{PreferredType: ApplicationJson}) return } - sub := SubscriptionAction{} - if err := json.NewDecoder(r.Body).Decode(&sub); err != nil { - h.responseErr(w, r, &ErrInvalidBody{}) + sub := structs.SubscriptionAction{} + if err := easyjson.UnmarshalFromReader(r.Body, &sub); err != nil { + h.responseErr(w, r, &errHTTP.ErrInvalidBody{}) return } defer r.Body.Close() @@ -146,7 +139,7 @@ func GetOpts(r *http.Request) (*userEntity.SubscriptionOpts, error) { opts.Count = maxCount } if len(invalidParams) > 0 { - return nil, &ErrInvalidQueryParam{invalidParams} + return nil, &errHTTP.ErrInvalidQueryParam{invalidParams} } return opts, nil } diff --git a/internal/pkg/entity/board/board.go b/internal/pkg/entity/board/board.go index 3ce9b66..d695468 100644 --- a/internal/pkg/entity/board/board.go +++ b/internal/pkg/entity/board/board.go @@ -7,6 +7,7 @@ import ( ) //go:generate easyjson board.go + //easyjson:json type Board struct { ID int `json:"id,omitempty" example:"15"` @@ -19,6 +20,7 @@ type Board struct { DeletedAt *time.Time `json:"-"` } +//easyjson:json type BoardWithContent struct { BoardInfo Board PinsNumber int diff --git a/internal/pkg/entity/board/board_easyjson.go b/internal/pkg/entity/board/board_easyjson.go index 7e6adbe..12d08ef 100644 --- a/internal/pkg/entity/board/board_easyjson.go +++ b/internal/pkg/entity/board/board_easyjson.go @@ -18,7 +18,158 @@ var ( _ easyjson.Marshaler ) -func easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(in *jlexer.Lexer, out *Board) { +func easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(in *jlexer.Lexer, out *BoardWithContent) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "BoardInfo": + (out.BoardInfo).UnmarshalEasyJSON(in) + case "PinsNumber": + out.PinsNumber = int(in.Int()) + case "Pins": + if in.IsNull() { + in.Skip() + out.Pins = nil + } else { + in.Delim('[') + if out.Pins == nil { + if !in.IsDelim(']') { + out.Pins = make([]string, 0, 4) + } else { + out.Pins = []string{} + } + } else { + out.Pins = (out.Pins)[:0] + } + for !in.IsDelim(']') { + var v1 string + v1 = string(in.String()) + out.Pins = append(out.Pins, v1) + in.WantComma() + } + in.Delim(']') + } + case "TagTitles": + if in.IsNull() { + in.Skip() + out.TagTitles = nil + } else { + in.Delim('[') + if out.TagTitles == nil { + if !in.IsDelim(']') { + out.TagTitles = make([]string, 0, 4) + } else { + out.TagTitles = []string{} + } + } else { + out.TagTitles = (out.TagTitles)[:0] + } + for !in.IsDelim(']') { + var v2 string + v2 = string(in.String()) + out.TagTitles = append(out.TagTitles, v2) + in.WantComma() + } + in.Delim(']') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(out *jwriter.Writer, in BoardWithContent) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"BoardInfo\":" + out.RawString(prefix[1:]) + (in.BoardInfo).MarshalEasyJSON(out) + } + { + const prefix string = ",\"PinsNumber\":" + out.RawString(prefix) + out.Int(int(in.PinsNumber)) + } + { + const prefix string = ",\"Pins\":" + out.RawString(prefix) + if in.Pins == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v3, v4 := range in.Pins { + if v3 > 0 { + out.RawByte(',') + } + out.String(string(v4)) + } + out.RawByte(']') + } + } + { + const prefix string = ",\"TagTitles\":" + out.RawString(prefix) + if in.TagTitles == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v5, v6 := range in.TagTitles { + if v5 > 0 { + out.RawByte(',') + } + out.String(string(v6)) + } + out.RawByte(']') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v BoardWithContent) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v BoardWithContent) MarshalEasyJSON(w *jwriter.Writer) { + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *BoardWithContent) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *BoardWithContent) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(l, v) +} +func easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard1(in *jlexer.Lexer, out *Board) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -69,7 +220,7 @@ func easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoa in.Consumed() } } -func easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(out *jwriter.Writer, in Board) { +func easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard1(out *jwriter.Writer, in Board) { out.RawByte('{') first := true _ = first @@ -120,23 +271,23 @@ func easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoa // MarshalJSON supports json.Marshaler interface func (v Board) MarshalJSON() ([]byte, error) { w := jwriter.Writer{} - easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(&w, v) + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard1(&w, v) return w.Buffer.BuildBytes(), w.Error } // MarshalEasyJSON supports easyjson.Marshaler interface func (v Board) MarshalEasyJSON(w *jwriter.Writer) { - easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(w, v) + easyjson202377feEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard1(w, v) } // UnmarshalJSON supports json.Unmarshaler interface func (v *Board) UnmarshalJSON(data []byte) error { r := jlexer.Lexer{Data: data} - easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(&r, v) + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard1(&r, v) return r.Error() } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface func (v *Board) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard(l, v) + easyjson202377feDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityBoard1(l, v) } diff --git a/internal/pkg/entity/comment/comment_easyjson.go b/internal/pkg/entity/comment/comment_easyjson.go index c3bb7ab..78723f0 100644 --- a/internal/pkg/entity/comment/comment_easyjson.go +++ b/internal/pkg/entity/comment/comment_easyjson.go @@ -47,7 +47,7 @@ func easyjsonE9abebc9DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityCom if out.Author == nil { out.Author = new(user.User) } - easyjsonE9abebc9DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser(in, out.Author) + (*out.Author).UnmarshalEasyJSON(in) } case "pinID": out.PinID = int(in.Int()) @@ -80,7 +80,7 @@ func easyjsonE9abebc9EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityCom if in.Author == nil { out.RawString("null") } else { - easyjsonE9abebc9EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser(out, *in.Author) + (*in.Author).MarshalEasyJSON(out) } } { @@ -119,106 +119,3 @@ func (v *Comment) UnmarshalJSON(data []byte) error { func (v *Comment) UnmarshalEasyJSON(l *jlexer.Lexer) { easyjsonE9abebc9DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityComment(l, v) } -func easyjsonE9abebc9DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser(in *jlexer.Lexer, out *user.User) { - isTopLevel := in.IsStart() - if in.IsNull() { - if isTopLevel { - in.Consumed() - } - in.Skip() - return - } - in.Delim('{') - for !in.IsDelim('}') { - key := in.UnsafeFieldName(false) - in.WantColon() - if in.IsNull() { - in.Skip() - in.WantComma() - continue - } - switch key { - case "id": - out.ID = int(in.Int()) - case "username": - out.Username = string(in.String()) - case "name": - if data := in.Raw(); in.Ok() { - in.AddError((out.Name).UnmarshalJSON(data)) - } - case "surname": - if data := in.Raw(); in.Ok() { - in.AddError((out.Surname).UnmarshalJSON(data)) - } - case "email": - out.Email = string(in.String()) - case "avatar": - out.Avatar = string(in.String()) - case "about_me": - if data := in.Raw(); in.Ok() { - in.AddError((out.AboutMe).UnmarshalJSON(data)) - } - case "password": - out.Password = string(in.String()) - default: - in.SkipRecursive() - } - in.WantComma() - } - in.Delim('}') - if isTopLevel { - in.Consumed() - } -} -func easyjsonE9abebc9EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser(out *jwriter.Writer, in user.User) { - out.RawByte('{') - first := true - _ = first - if in.ID != 0 { - const prefix string = ",\"id\":" - first = false - out.RawString(prefix[1:]) - out.Int(int(in.ID)) - } - { - const prefix string = ",\"username\":" - if first { - first = false - out.RawString(prefix[1:]) - } else { - out.RawString(prefix) - } - out.String(string(in.Username)) - } - if true { - const prefix string = ",\"name\":" - out.RawString(prefix) - out.Raw((in.Name).MarshalJSON()) - } - if true { - const prefix string = ",\"surname\":" - out.RawString(prefix) - out.Raw((in.Surname).MarshalJSON()) - } - if in.Email != "" { - const prefix string = ",\"email\":" - out.RawString(prefix) - out.String(string(in.Email)) - } - { - const prefix string = ",\"avatar\":" - out.RawString(prefix) - out.String(string(in.Avatar)) - } - if true { - const prefix string = ",\"about_me\":" - out.RawString(prefix) - out.Raw((in.AboutMe).MarshalJSON()) - } - if in.Password != "" { - const prefix string = ",\"password\":" - out.RawString(prefix) - out.String(string(in.Password)) - } - out.RawByte('}') -} diff --git a/internal/pkg/entity/search/search.go b/internal/pkg/entity/search/search.go index 76b0c6a..478aabe 100644 --- a/internal/pkg/entity/search/search.go +++ b/internal/pkg/entity/search/search.go @@ -8,6 +8,8 @@ import ( "github.com/microcosm-cc/bluemonday" ) +//go:generate easyjson search.go + type Template string func (t *Template) Validate() bool { @@ -26,12 +28,14 @@ func (t *Template) GetSubStrings(sep string) []string { return strings.Split(string(*t), sep) } +//easyjson:json type BoardForSearch struct { BoardHeader board.Board PinsNumber int `json:"pins_number"` PreviewPins []string `json:"pins"` } +//easyjson:json type PinForSearch struct { ID int `json:"id"` Title string `json:"title"` @@ -39,6 +43,7 @@ type PinForSearch struct { Likes int `json:"likes"` } +//easyjson:json type UserForSearch struct { ID int `json:"id"` Username string `json:"username"` diff --git a/internal/pkg/entity/search/search_easyjson.go b/internal/pkg/entity/search/search_easyjson.go new file mode 100644 index 0000000..497b75f --- /dev/null +++ b/internal/pkg/entity/search/search_easyjson.go @@ -0,0 +1,312 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package search + +import ( + json "encoding/json" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjsonD4176298DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch(in *jlexer.Lexer, out *UserForSearch) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "id": + out.ID = int(in.Int()) + case "username": + out.Username = string(in.String()) + case "avatar": + out.Avatar = string(in.String()) + case "subscribers": + out.SubsCount = int(in.Int()) + case "is_subscribed": + out.HasSubscribeFromCurUser = bool(in.Bool()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonD4176298EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch(out *jwriter.Writer, in UserForSearch) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"id\":" + out.RawString(prefix[1:]) + out.Int(int(in.ID)) + } + { + const prefix string = ",\"username\":" + out.RawString(prefix) + out.String(string(in.Username)) + } + { + const prefix string = ",\"avatar\":" + out.RawString(prefix) + out.String(string(in.Avatar)) + } + { + const prefix string = ",\"subscribers\":" + out.RawString(prefix) + out.Int(int(in.SubsCount)) + } + { + const prefix string = ",\"is_subscribed\":" + out.RawString(prefix) + out.Bool(bool(in.HasSubscribeFromCurUser)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v UserForSearch) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonD4176298EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v UserForSearch) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonD4176298EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *UserForSearch) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonD4176298DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *UserForSearch) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonD4176298DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch(l, v) +} +func easyjsonD4176298DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch1(in *jlexer.Lexer, out *PinForSearch) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "id": + out.ID = int(in.Int()) + case "title": + out.Title = string(in.String()) + case "picture": + out.Picture = string(in.String()) + case "likes": + out.Likes = int(in.Int()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonD4176298EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch1(out *jwriter.Writer, in PinForSearch) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"id\":" + out.RawString(prefix[1:]) + out.Int(int(in.ID)) + } + { + const prefix string = ",\"title\":" + out.RawString(prefix) + out.String(string(in.Title)) + } + { + const prefix string = ",\"picture\":" + out.RawString(prefix) + out.String(string(in.Picture)) + } + { + const prefix string = ",\"likes\":" + out.RawString(prefix) + out.Int(int(in.Likes)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v PinForSearch) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonD4176298EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch1(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v PinForSearch) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonD4176298EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch1(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *PinForSearch) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonD4176298DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch1(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *PinForSearch) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonD4176298DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch1(l, v) +} +func easyjsonD4176298DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch2(in *jlexer.Lexer, out *BoardForSearch) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "BoardHeader": + (out.BoardHeader).UnmarshalEasyJSON(in) + case "pins_number": + out.PinsNumber = int(in.Int()) + case "pins": + if in.IsNull() { + in.Skip() + out.PreviewPins = nil + } else { + in.Delim('[') + if out.PreviewPins == nil { + if !in.IsDelim(']') { + out.PreviewPins = make([]string, 0, 4) + } else { + out.PreviewPins = []string{} + } + } else { + out.PreviewPins = (out.PreviewPins)[:0] + } + for !in.IsDelim(']') { + var v1 string + v1 = string(in.String()) + out.PreviewPins = append(out.PreviewPins, v1) + in.WantComma() + } + in.Delim(']') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonD4176298EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch2(out *jwriter.Writer, in BoardForSearch) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"BoardHeader\":" + out.RawString(prefix[1:]) + (in.BoardHeader).MarshalEasyJSON(out) + } + { + const prefix string = ",\"pins_number\":" + out.RawString(prefix) + out.Int(int(in.PinsNumber)) + } + { + const prefix string = ",\"pins\":" + out.RawString(prefix) + if in.PreviewPins == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v2, v3 := range in.PreviewPins { + if v2 > 0 { + out.RawByte(',') + } + out.String(string(v3)) + } + out.RawByte(']') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v BoardForSearch) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonD4176298EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch2(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v BoardForSearch) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonD4176298EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch2(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *BoardForSearch) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonD4176298DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch2(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *BoardForSearch) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonD4176298DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntitySearch2(l, v) +} diff --git a/internal/pkg/entity/user/user.go b/internal/pkg/entity/user/user.go index 70f2e14..5a636fc 100644 --- a/internal/pkg/entity/user/user.go +++ b/internal/pkg/entity/user/user.go @@ -5,8 +5,11 @@ import ( "github.com/microcosm-cc/bluemonday" ) +//go:generate easyjson user.go + const UserUnknown = -1 +//easyjson:json type User struct { ID int `json:"id,omitempty" example:"123"` Username string `json:"username" example:"Green"` @@ -18,6 +21,7 @@ type User struct { Password string `json:"password,omitempty" example:"pass123"` } // @name User +//easyjson:json type SubscriptionUser struct { ID int `json:"id"` Username string `json:"username"` diff --git a/internal/pkg/entity/user/user_easyjson.go b/internal/pkg/entity/user/user_easyjson.go new file mode 100644 index 0000000..e8b0dae --- /dev/null +++ b/internal/pkg/entity/user/user_easyjson.go @@ -0,0 +1,233 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package user + +import ( + json "encoding/json" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser(in *jlexer.Lexer, out *User) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "id": + out.ID = int(in.Int()) + case "username": + out.Username = string(in.String()) + case "name": + if data := in.Raw(); in.Ok() { + in.AddError((out.Name).UnmarshalJSON(data)) + } + case "surname": + if data := in.Raw(); in.Ok() { + in.AddError((out.Surname).UnmarshalJSON(data)) + } + case "email": + out.Email = string(in.String()) + case "avatar": + out.Avatar = string(in.String()) + case "about_me": + if data := in.Raw(); in.Ok() { + in.AddError((out.AboutMe).UnmarshalJSON(data)) + } + case "password": + out.Password = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser(out *jwriter.Writer, in User) { + out.RawByte('{') + first := true + _ = first + if in.ID != 0 { + const prefix string = ",\"id\":" + first = false + out.RawString(prefix[1:]) + out.Int(int(in.ID)) + } + { + const prefix string = ",\"username\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.Username)) + } + if true { + const prefix string = ",\"name\":" + out.RawString(prefix) + out.Raw((in.Name).MarshalJSON()) + } + if true { + const prefix string = ",\"surname\":" + out.RawString(prefix) + out.Raw((in.Surname).MarshalJSON()) + } + if in.Email != "" { + const prefix string = ",\"email\":" + out.RawString(prefix) + out.String(string(in.Email)) + } + { + const prefix string = ",\"avatar\":" + out.RawString(prefix) + out.String(string(in.Avatar)) + } + if true { + const prefix string = ",\"about_me\":" + out.RawString(prefix) + out.Raw((in.AboutMe).MarshalJSON()) + } + if in.Password != "" { + const prefix string = ",\"password\":" + out.RawString(prefix) + out.String(string(in.Password)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v User) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v User) MarshalEasyJSON(w *jwriter.Writer) { + easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *User) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *User) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser(l, v) +} +func easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser1(in *jlexer.Lexer, out *SubscriptionUser) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "id": + out.ID = int(in.Int()) + case "username": + out.Username = string(in.String()) + case "avatar": + out.Avatar = string(in.String()) + case "is_subscribed": + out.HasSubscribeFromCurUser = bool(in.Bool()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser1(out *jwriter.Writer, in SubscriptionUser) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"id\":" + out.RawString(prefix[1:]) + out.Int(int(in.ID)) + } + { + const prefix string = ",\"username\":" + out.RawString(prefix) + out.String(string(in.Username)) + } + { + const prefix string = ",\"avatar\":" + out.RawString(prefix) + out.String(string(in.Avatar)) + } + { + const prefix string = ",\"is_subscribed\":" + out.RawString(prefix) + out.Bool(bool(in.HasSubscribeFromCurUser)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v SubscriptionUser) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser1(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v SubscriptionUser) MarshalEasyJSON(w *jwriter.Writer) { + easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser1(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *SubscriptionUser) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser1(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *SubscriptionUser) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgEntityUser1(l, v) +} From ea2a4d0dbe84626d4e699859fbcf20ca5dfd196a Mon Sep 17 00:00:00 2001 From: Gvidow Date: Sun, 17 Dec 2023 13:07:49 +0300 Subject: [PATCH 11/21] TP-8da update: returned user from and to when deleting message --- internal/pkg/usecase/message/usecase.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/internal/pkg/usecase/message/usecase.go b/internal/pkg/usecase/message/usecase.go index 552d8c8..00bc0fc 100644 --- a/internal/pkg/usecase/message/usecase.go +++ b/internal/pkg/usecase/message/usecase.go @@ -31,8 +31,6 @@ type Usecase interface { SubscribeUserToAllChats(ctx context.Context, userID int) (<-chan EventMessage, error) } -const _topicChat = "chat" - type EventMessage struct { Type string Message *entity.Message @@ -191,13 +189,14 @@ func (m *messageCase) receiveFromSubClient(ctx context.Context, userID int, subC evMsg = EventMessage{ Type: msgObjID.Type, } + + evMsg.Message, err = m.GetMessage(ctx, userID, msgObjID.MessageID) + if err != nil { + m.log.Error(err.Error()) + } + if evMsg.Type == "delete" { - evMsg.Message = &entity.Message{ID: msgObjID.MessageID} - } else { - evMsg.Message, err = m.GetMessage(ctx, userID, msgObjID.MessageID) - if err != nil { - m.log.Error(err.Error()) - } + evMsg.Message.Content.String = "" } chanEvMsg <- evMsg From d63df1b8277f245d81fdd6ea4d7cc4b16e8b5c4b Mon Sep 17 00:00:00 2001 From: Gvidow <96253031+Gvidow@users.noreply.github.com> Date: Tue, 19 Dec 2023 11:41:40 +0300 Subject: [PATCH 12/21] Update websocket.go: delete unused package "os" --- internal/pkg/delivery/websocket/websocket.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/pkg/delivery/websocket/websocket.go b/internal/pkg/delivery/websocket/websocket.go index 5d55376..bd7db73 100644 --- a/internal/pkg/delivery/websocket/websocket.go +++ b/internal/pkg/delivery/websocket/websocket.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net/http" - "os" "time" ws "nhooyr.io/websocket" From 2d1c6d21c9c9aa2b6f97e67b1c24bfe15188aa5d Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Tue, 19 Dec 2023 13:42:56 +0300 Subject: [PATCH 13/21] TP-6ec_easyjson: add rest easyjson --- internal/pkg/delivery/http/v1/auth.go | 8 +- internal/pkg/delivery/http/v1/auth_test.go | 71 +++--- internal/pkg/delivery/http/v1/board.go | 2 +- internal/pkg/delivery/http/v1/comment.go | 3 - internal/pkg/delivery/http/v1/pin.go | 5 +- internal/pkg/delivery/http/v1/pin_test.go | 17 +- internal/pkg/delivery/http/v1/profile.go | 31 +-- internal/pkg/delivery/http/v1/profile_test.go | 5 +- .../pkg/delivery/http/v1/structs/board.go | 43 ++++ .../http/v1/structs/board_validation.go | 48 ---- .../pkg/delivery/http/v1/structs/response.go | 2 +- internal/pkg/delivery/http/v1/structs/user.go | 23 ++ .../delivery/http/v1/structs/user_easyjson.go | 221 ++++++++++++++++++ internal/pkg/usecase/pin/update.go | 11 +- internal/pkg/usecase/pin/update_easyjson.go | 174 ++++++++++++++ internal/pkg/usecase/user/credentials.go | 7 +- .../pkg/usecase/user/credentials_easyjson.go | 92 ++++++++ internal/pkg/usecase/user/info.go | 13 +- internal/pkg/usecase/user/info_easyjson.go | 192 +++++++++++++++ 19 files changed, 828 insertions(+), 140 deletions(-) delete mode 100644 internal/pkg/delivery/http/v1/structs/board_validation.go create mode 100644 internal/pkg/delivery/http/v1/structs/user.go create mode 100644 internal/pkg/delivery/http/v1/structs/user_easyjson.go create mode 100644 internal/pkg/usecase/pin/update_easyjson.go create mode 100644 internal/pkg/usecase/user/credentials_easyjson.go create mode 100644 internal/pkg/usecase/user/info_easyjson.go diff --git a/internal/pkg/delivery/http/v1/auth.go b/internal/pkg/delivery/http/v1/auth.go index 6f536a7..0c0149a 100644 --- a/internal/pkg/delivery/http/v1/auth.go +++ b/internal/pkg/delivery/http/v1/auth.go @@ -1,7 +1,6 @@ package v1 import ( - "encoding/json" "net/http" "time" @@ -10,6 +9,7 @@ import ( "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/middleware/auth" usecase "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/usecase/user" log "github.com/go-park-mail-ru/2023_2_OND_team/pkg/logger" + "github.com/mailru/easyjson" ) // Login godoc @@ -56,8 +56,8 @@ func (h *HandlerHTTP) CheckLogin(w http.ResponseWriter, r *http.Request) { func (h *HandlerHTTP) Login(w http.ResponseWriter, r *http.Request) { logger := h.getRequestLogger(r) - params := usecase.UserCredentials{} - err := json.NewDecoder(r.Body).Decode(¶ms) + params := &usecase.UserCredentials{} + err := easyjson.UnmarshalFromReader(r.Body, params) defer r.Body.Close() if err != nil { logger.Info("failed to parse parameters", log.F{"error", err.Error()}) @@ -122,7 +122,7 @@ func (h *HandlerHTTP) Signup(w http.ResponseWriter, r *http.Request) { logger := h.getRequestLogger(r) user := &user.User{} - err := json.NewDecoder(r.Body).Decode(user) + err := easyjson.UnmarshalFromReader(r.Body, user) defer r.Body.Close() if err != nil { logger.Info("failed to parse parameters", log.F{"error", err.Error()}) diff --git a/internal/pkg/delivery/http/v1/auth_test.go b/internal/pkg/delivery/http/v1/auth_test.go index 29949ea..95c6744 100644 --- a/internal/pkg/delivery/http/v1/auth_test.go +++ b/internal/pkg/delivery/http/v1/auth_test.go @@ -10,6 +10,7 @@ import ( "strings" "testing" + "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/structs" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/repository/ramrepo" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/usecase/session" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/usecase/user" @@ -45,7 +46,7 @@ func TestCheckLogin(t *testing.T) { badCases := []struct { name string cookie *http.Cookie - expResp JsonErrResponse + expResp structs.JsonErrResponse }{ { "sending empty cookie", @@ -53,7 +54,7 @@ func TestCheckLogin(t *testing.T) { Name: "", Value: "", }, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "no user was found for this session", Code: "no_auth", @@ -65,7 +66,7 @@ func TestCheckLogin(t *testing.T) { Name: "session_key", Value: "doesn't exist", }, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "no user was found for this session", Code: "no_auth", @@ -77,7 +78,7 @@ func TestCheckLogin(t *testing.T) { Name: "session_key", Value: "f4280a941b664d02", }, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "no user was found for this session", Code: "no_auth", @@ -93,7 +94,7 @@ func TestCheckLogin(t *testing.T) { service.CheckLogin(w, req) - var actualResp JsonErrResponse + var actualResp structs.JsonErrResponse json.NewDecoder(w.Result().Body).Decode(&actualResp) require.Equal(t, tCase.expResp, actualResp) }) @@ -116,12 +117,12 @@ func testLogin(t *testing.T) { goodCases := []struct { name string rawBody string - expResp JsonResponse + expResp structs.JsonResponse }{ { "providing correct and valid user credentials", `{"username":"dogsLover", "password":"big_string"}`, - JsonResponse{ + structs.JsonResponse{ Status: "ok", Message: "a new session has been created for the user", Body: nil, @@ -136,7 +137,7 @@ func testLogin(t *testing.T) { service.Login(w, req) - var actualResp JsonResponse + var actualResp structs.JsonResponse json.NewDecoder(w.Result().Body).Decode(&actualResp) require.Equal(t, tCase.expResp, actualResp) require.True(t, checkAuthCookie(w.Result().Cookies())) @@ -146,12 +147,12 @@ func testLogin(t *testing.T) { badCases := []struct { name string rawBody string - expResp JsonErrResponse + expResp structs.JsonErrResponse }{ { "providing invalid credentials - broken body", "{'username': 'dogsLover', 'password': 'big_string'", - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "the correct username and password are expected to be received in JSON format", Code: "parse_body", @@ -160,7 +161,7 @@ func testLogin(t *testing.T) { { "providing invalid credentials - no username", `{"password":"big_string"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "invalid user credentials", Code: "invalid_credentials", @@ -169,7 +170,7 @@ func testLogin(t *testing.T) { { "providing invalid credentials - no password", `{"username":"dogsLover"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "invalid user credentials", Code: "invalid_credentials", @@ -178,7 +179,7 @@ func testLogin(t *testing.T) { { "providing invalid credentials - short username", `{"username":"do", "password":"big_string"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "invalid user credentials", Code: "invalid_credentials", @@ -187,7 +188,7 @@ func testLogin(t *testing.T) { { "providing invalid credentials - long username", `{"username":"dojsbrjfbdrjhbhjldrbgbdrhjgbdjrbgjdhbgjhdbrghbdhj,gbdhjrbgjhdbvkvghkevfghjdvrfhvdhrvbjdfgdrgdr","password":"big_string"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "invalid user credentials", Code: "invalid_credentials", @@ -196,7 +197,7 @@ func testLogin(t *testing.T) { { "providing invalid credentials - short password", `{"username":"dogsLover","password":"bi"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "invalid user credentials", Code: "invalid_credentials", @@ -205,7 +206,7 @@ func testLogin(t *testing.T) { { "providing invalid credentials - long password", `{"username":"dogsLover","password":"biyugsgrusgubskhvfhkdgvfgvdvrjgbsjhgjkshzkljfskfwjkhkfjisuidgoquakflsjuzeofiow3i"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "invalid user credentials", Code: "invalid_credentials", @@ -214,7 +215,7 @@ func testLogin(t *testing.T) { { "providing incorrect credentials - no user with such credentials", `{"username":"dogsLover", "password":"doesn't_exist"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "incorrect user credentials", Code: "bad_credentials", @@ -229,7 +230,7 @@ func testLogin(t *testing.T) { service.Login(w, req) - var actualResp JsonErrResponse + var actualResp structs.JsonErrResponse json.NewDecoder(w.Result().Body).Decode(&actualResp) require.Equal(t, tCase.expResp, actualResp) require.False(t, checkAuthCookie(w.Result().Cookies())) @@ -252,12 +253,12 @@ func testSignUp(t *testing.T) { goodCases := []struct { name string rawBody string - expResp JsonResponse + expResp structs.JsonResponse }{ { "providing correct and valid data for signup", `{"username":"newbie", "password":"getHigh123", "email":"world@uandex.ru"}`, - JsonResponse{ + structs.JsonResponse{ Status: "ok", Message: "the user has been successfully registered", Body: nil, @@ -272,7 +273,7 @@ func testSignUp(t *testing.T) { service.Signup(w, req) - var actualResp JsonResponse + var actualResp structs.JsonResponse json.NewDecoder(w.Result().Body).Decode(&actualResp) require.Equal(t, tCase.expResp, actualResp) }) @@ -281,12 +282,12 @@ func testSignUp(t *testing.T) { badCases := []struct { name string rawBody string - expResp JsonErrResponse + expResp structs.JsonErrResponse }{ { "user with such data already exists", `{"username":"dogsLover", "password":"big_string", "email":"dogslove@gmail.com"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "there is already an account with this username or email", Code: "uniq_fields", @@ -295,7 +296,7 @@ func testSignUp(t *testing.T) { { "invalid data - broken body", `{"username":"dogsLover", "password":"big_string", "email":"dogslove@gmail.com"`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "the correct username, email and password are expected to be received in JSON format", Code: "parse_body", @@ -304,7 +305,7 @@ func testSignUp(t *testing.T) { { "invalid data - no username", `{"password":"big_string", "email":"dogslove@gmail.com"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "username", Code: "invalid_params", @@ -313,7 +314,7 @@ func testSignUp(t *testing.T) { { "invalid data - no username, password", `{"email":"dogslove@gmail.com"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "password,username", Code: "invalid_params", @@ -322,7 +323,7 @@ func testSignUp(t *testing.T) { { "invalid data - short username", `{"username":"sh", "password":"big_string", "email":"dogslove@gmail.com"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "username", Code: "invalid_params", @@ -331,7 +332,7 @@ func testSignUp(t *testing.T) { { "invalid data - incorrect email", `{"username":"sh", "password":"big_string", "email":"dog"}`, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "email,username", Code: "invalid_params", @@ -346,7 +347,7 @@ func testSignUp(t *testing.T) { service.Signup(w, req) - var actualResp JsonErrResponse + var actualResp structs.JsonErrResponse json.NewDecoder(w.Result().Body).Decode(&actualResp) require.Equal(t, tCase.expResp, actualResp) }) @@ -368,7 +369,7 @@ func testLogout(t *testing.T) { goodCases := []struct { name string cookie *http.Cookie - expResp JsonResponse + expResp structs.JsonResponse }{ { "user is logged in - providing valid cookie", @@ -376,7 +377,7 @@ func testLogout(t *testing.T) { Name: "session_key", Value: "461afabf38b3147c", }, - JsonResponse{ + structs.JsonResponse{ Status: "ok", Message: "the user has successfully logged out", Body: nil, @@ -392,7 +393,7 @@ func testLogout(t *testing.T) { service.Logout(w, req) - var actualResp JsonResponse + var actualResp structs.JsonResponse json.NewDecoder(w.Result().Body).Decode(&actualResp) require.Equal(t, tCase.expResp, actualResp) }) @@ -401,7 +402,7 @@ func testLogout(t *testing.T) { badCases := []struct { name string cookie *http.Cookie - expResp JsonErrResponse + expResp structs.JsonErrResponse }{ { "user isn't logged in - providing invalid cookie", @@ -409,7 +410,7 @@ func testLogout(t *testing.T) { Name: "not_auth_cookie", Value: "blablalba", }, - JsonErrResponse{ + structs.JsonErrResponse{ Status: "error", Message: "to log out, you must first log in", Code: "no_auth", @@ -425,7 +426,7 @@ func testLogout(t *testing.T) { service.Logout(w, req) - var actualResp JsonErrResponse + var actualResp structs.JsonErrResponse json.NewDecoder(w.Result().Body).Decode(&actualResp) require.Equal(t, tCase.expResp, actualResp) }) diff --git a/internal/pkg/delivery/http/v1/board.go b/internal/pkg/delivery/http/v1/board.go index f55db48..2b02193 100644 --- a/internal/pkg/delivery/http/v1/board.go +++ b/internal/pkg/delivery/http/v1/board.go @@ -349,12 +349,12 @@ func (h *HandlerHTTP) DeletePinFromBoard(w http.ResponseWriter, r *http.Request) delPinFromBoard := structs.DeletePinFromBoard{} err = easyjson.UnmarshalFromReader(r.Body, &delPinFromBoard) + defer r.Body.Close() if err != nil { code, message := errHTTP.GetErrCodeMessage(errHTTP.ErrBadBody) responseError(w, code, message) return } - defer r.Body.Close() err = h.boardCase.DeletePinFromBoard(r.Context(), int(boardID), delPinFromBoard.PinID) if err != nil { diff --git a/internal/pkg/delivery/http/v1/comment.go b/internal/pkg/delivery/http/v1/comment.go index 60e1b8d..a5dd834 100644 --- a/internal/pkg/delivery/http/v1/comment.go +++ b/internal/pkg/delivery/http/v1/comment.go @@ -1,7 +1,6 @@ package v1 import ( - "fmt" "net/http" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/entity/comment" @@ -24,9 +23,7 @@ func (h *HandlerHTTP) WriteComment(w http.ResponseWriter, r *http.Request) { } comment := &comment.Comment{} - err = easyjson.UnmarshalFromReader(r.Body, comment) - fmt.Println(comment.Content) defer r.Body.Close() if err != nil { logger.Warn(err.Error()) diff --git a/internal/pkg/delivery/http/v1/pin.go b/internal/pkg/delivery/http/v1/pin.go index f9ba931..19b2831 100644 --- a/internal/pkg/delivery/http/v1/pin.go +++ b/internal/pkg/delivery/http/v1/pin.go @@ -1,12 +1,12 @@ package v1 import ( - "encoding/json" "net/http" "strconv" "strings" chi "github.com/go-chi/chi/v5" + "github.com/mailru/easyjson" entity "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/entity/pin" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/entity/user" @@ -129,8 +129,7 @@ func (h *HandlerHTTP) EditPin(w http.ResponseWriter, r *http.Request) { _, _ = userID, pinID pinUpdate := &usecase.PinUpdateData{} - - err = json.NewDecoder(r.Body).Decode(pinUpdate) + err = easyjson.UnmarshalFromReader(r.Body, pinUpdate) defer r.Body.Close() if err != nil { logger.Info(err.Error()) diff --git a/internal/pkg/delivery/http/v1/pin_test.go b/internal/pkg/delivery/http/v1/pin_test.go index 9f5bf20..358d6d2 100644 --- a/internal/pkg/delivery/http/v1/pin_test.go +++ b/internal/pkg/delivery/http/v1/pin_test.go @@ -9,6 +9,7 @@ import ( "strconv" "testing" + "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/structs" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/repository/ramrepo" pinCase "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/usecase/pin" "github.com/go-park-mail-ru/2023_2_OND_team/pkg/logger" @@ -30,11 +31,11 @@ func TestGetPins(t *testing.T) { badCases := []struct { rawURL string - expResp JsonErrResponse + expResp structs.JsonErrResponse }{ { rawURL: fmt.Sprintf("%s?count=%d&lastID=%d", rawUrl, 0, 3), - expResp: JsonErrResponse{ + expResp: structs.JsonErrResponse{ Status: "error", Message: "expected parameters: count(positive integer: [1; 1000]), maxID, minID(positive integers, the absence of these parameters is equal to the value 0)", Code: "bad_params", @@ -42,7 +43,7 @@ func TestGetPins(t *testing.T) { }, { rawURL: fmt.Sprintf("%s?count=%d&lastID=%d", rawUrl, -2, 3), - expResp: JsonErrResponse{ + expResp: structs.JsonErrResponse{ Status: "error", Message: "expected parameters: count(positive integer: [1; 1000]), maxID, minID(positive integers, the absence of these parameters is equal to the value 0)", Code: "bad_params", @@ -50,7 +51,7 @@ func TestGetPins(t *testing.T) { }, { rawURL: fmt.Sprintf("%s?count=%d&lastID=%d", rawUrl, 213123, 3), - expResp: JsonErrResponse{ + expResp: structs.JsonErrResponse{ Status: "error", Message: "expected parameters: count(positive integer: [1; 1000]), maxID, minID(positive integers, the absence of these parameters is equal to the value 0)", Code: "bad_params", @@ -58,7 +59,7 @@ func TestGetPins(t *testing.T) { }, { rawURL: fmt.Sprintf("%s?count=%d&lastID=%d", rawUrl, 0, -1), - expResp: JsonErrResponse{ + expResp: structs.JsonErrResponse{ Status: "error", Message: "expected parameters: count(positive integer: [1; 1000]), maxID, minID(positive integers, the absence of these parameters is equal to the value 0)", Code: "bad_params", @@ -66,7 +67,7 @@ func TestGetPins(t *testing.T) { }, { rawURL: fmt.Sprintf("%s?count=&lastID=%d", rawUrl, 3), - expResp: JsonErrResponse{ + expResp: structs.JsonErrResponse{ Status: "error", Message: "expected parameters: count(positive integer: [1; 1000]), maxID, minID(positive integers, the absence of these parameters is equal to the value 0)", Code: "bad_params", @@ -74,7 +75,7 @@ func TestGetPins(t *testing.T) { }, { rawURL: fmt.Sprintf("%s?lastID=%d", rawUrl, 3), - expResp: JsonErrResponse{ + expResp: structs.JsonErrResponse{ Status: "error", Message: "expected parameters: count(positive integer: [1; 1000]), maxID, minID(positive integers, the absence of these parameters is equal to the value 0)", Code: "bad_params", @@ -90,7 +91,7 @@ func TestGetPins(t *testing.T) { resp := w.Result() body, _ := io.ReadAll(resp.Body) - var actualResp JsonErrResponse + var actualResp structs.JsonErrResponse json.Unmarshal(body, &actualResp) require.Equal(t, tCase.expResp, actualResp) diff --git a/internal/pkg/delivery/http/v1/profile.go b/internal/pkg/delivery/http/v1/profile.go index 66ab2ab..be60ccb 100644 --- a/internal/pkg/delivery/http/v1/profile.go +++ b/internal/pkg/delivery/http/v1/profile.go @@ -1,39 +1,22 @@ package v1 import ( - "encoding/json" "fmt" "net/http" "strconv" "github.com/go-chi/chi/v5" errHTTP "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/errors" + "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/structs" userEntity "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/entity/user" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/middleware/auth" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/usecase/user" log "github.com/go-park-mail-ru/2023_2_OND_team/pkg/logger" + "github.com/mailru/easyjson" ) -type UserInfo struct { - ID int `json:"id" example:"123"` - Username string `json:"username" example:"Snapshot"` - Avatar string `json:"avatar" example:"/pic1"` - Name string `json:"name" example:"Bob"` - Surname string `json:"surname" example:"Dylan"` - About string `json:"about" example:"Cool guy"` - IsSubscribed bool `json:"is_subscribed" example:"true"` - SubsCount int `json:"subscribers" example:"23"` -} - -type ProfileInfo struct { - ID int `json:"id" example:"1"` - Username string `json:"username" example:"baobab"` - Avatar string `json:"avatar" example:"/pic1"` - SubsCount int `json:"subscribers" example:"12"` -} - -func ToUserInfoFromService(user *userEntity.User, isSubscribed bool, subsCount int) UserInfo { - return UserInfo{ +func ToUserInfoFromService(user *userEntity.User, isSubscribed bool, subsCount int) structs.UserInfo { + return structs.UserInfo{ ID: user.ID, Username: user.Username, Avatar: user.Avatar, @@ -45,8 +28,8 @@ func ToUserInfoFromService(user *userEntity.User, isSubscribed bool, subsCount i } } -func ToProfileInfoFromService(user *userEntity.User, subsCount int) ProfileInfo { - return ProfileInfo{ +func ToProfileInfoFromService(user *userEntity.User, subsCount int) structs.ProfileInfo { + return structs.ProfileInfo{ ID: user.ID, Username: user.Username, Avatar: user.Avatar, @@ -83,7 +66,7 @@ func (h *HandlerHTTP) ProfileEditInfo(w http.ResponseWriter, r *http.Request) { userID := r.Context().Value(auth.KeyCurrentUserID).(int) data := &user.ProfileUpdateData{} - err := json.NewDecoder(r.Body).Decode(data) + err := easyjson.UnmarshalFromReader(r.Body, data) defer r.Body.Close() if err != nil { logger.Info("json decode: " + err.Error()) diff --git a/internal/pkg/delivery/http/v1/profile_test.go b/internal/pkg/delivery/http/v1/profile_test.go index d927e7f..5c87e00 100644 --- a/internal/pkg/delivery/http/v1/profile_test.go +++ b/internal/pkg/delivery/http/v1/profile_test.go @@ -11,6 +11,7 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/structs" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/entity/user" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/middleware/auth" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/usecase/user/mock" @@ -47,11 +48,11 @@ func TestGetProfileInfo(t *testing.T) { res := rec.Result() defer res.Body.Close() - actualBody := JsonResponse{Body: &user.User{}} + actualBody := structs.JsonResponse{Body: &user.User{}} err = json.NewDecoder(res.Body).Decode(&actualBody) require.NoError(t, err) fmt.Println(actualBody.Body) - wantBody := JsonResponse{ + wantBody := structs.JsonResponse{ Status: "ok", Message: "user data has been successfully received", Body: &wantUser, diff --git a/internal/pkg/delivery/http/v1/structs/board.go b/internal/pkg/delivery/http/v1/structs/board.go index e6aa540..9e42ece 100644 --- a/internal/pkg/delivery/http/v1/structs/board.go +++ b/internal/pkg/delivery/http/v1/structs/board.go @@ -2,6 +2,7 @@ package structs import ( "fmt" + "unicode" errHTTP "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1/errors" ) @@ -69,3 +70,45 @@ func (data *BoardData) Validate() error { } return nil } + +func isValidTagTitle(title string) bool { + if len(title) > 20 { + return false + } + + for _, sym := range title { + if !(unicode.IsNumber(sym) || unicode.IsLetter(sym) || unicode.IsPunct(sym) || unicode.IsSpace(sym)) { + return false + } + } + return true +} + +func checkIsValidTagTitles(titles []string) error { + if len(titles) > 7 { + return fmt.Errorf("too many titles") + } + + invalidTitles := make([]string, 0) + for _, title := range titles { + if !isValidTagTitle(title) { + invalidTitles = append(invalidTitles, title) + } + } + if len(invalidTitles) > 0 { + return fmt.Errorf("%v", invalidTitles) + } + return nil +} + +func isValidBoardTitle(title string) bool { + if len(title) == 0 || len(title) > 40 { + return false + } + for _, sym := range title { + if !(unicode.IsNumber(sym) || unicode.IsLetter(sym) || unicode.IsPunct(sym) || unicode.IsSpace(sym)) { + return false + } + } + return true +} diff --git a/internal/pkg/delivery/http/v1/structs/board_validation.go b/internal/pkg/delivery/http/v1/structs/board_validation.go deleted file mode 100644 index 6181434..0000000 --- a/internal/pkg/delivery/http/v1/structs/board_validation.go +++ /dev/null @@ -1,48 +0,0 @@ -package structs - -import ( - "fmt" - "unicode" -) - -func isValidTagTitle(title string) bool { - if len(title) > 20 { - return false - } - - for _, sym := range title { - if !(unicode.IsNumber(sym) || unicode.IsLetter(sym) || unicode.IsPunct(sym) || unicode.IsSpace(sym)) { - return false - } - } - return true -} - -func checkIsValidTagTitles(titles []string) error { - if len(titles) > 7 { - return fmt.Errorf("too many titles") - } - - invalidTitles := make([]string, 0) - for _, title := range titles { - if !isValidTagTitle(title) { - invalidTitles = append(invalidTitles, title) - } - } - if len(invalidTitles) > 0 { - return fmt.Errorf("%v", invalidTitles) - } - return nil -} - -func isValidBoardTitle(title string) bool { - if len(title) == 0 || len(title) > 40 { - return false - } - for _, sym := range title { - if !(unicode.IsNumber(sym) || unicode.IsLetter(sym) || unicode.IsPunct(sym) || unicode.IsSpace(sym)) { - return false - } - } - return true -} diff --git a/internal/pkg/delivery/http/v1/structs/response.go b/internal/pkg/delivery/http/v1/structs/response.go index e922b82..2be893b 100644 --- a/internal/pkg/delivery/http/v1/structs/response.go +++ b/internal/pkg/delivery/http/v1/structs/response.go @@ -1,6 +1,6 @@ package structs -//go:generate easyjson subscription.go +//go:generate easyjson response.go //easyjson:json type JsonResponse struct { diff --git a/internal/pkg/delivery/http/v1/structs/user.go b/internal/pkg/delivery/http/v1/structs/user.go new file mode 100644 index 0000000..3afc2aa --- /dev/null +++ b/internal/pkg/delivery/http/v1/structs/user.go @@ -0,0 +1,23 @@ +package structs + +//go:generate easyjson user.go + +//easyjson:json +type UserInfo struct { + ID int `json:"id" example:"123"` + Username string `json:"username" example:"Snapshot"` + Avatar string `json:"avatar" example:"/pic1"` + Name string `json:"name" example:"Bob"` + Surname string `json:"surname" example:"Dylan"` + About string `json:"about" example:"Cool guy"` + IsSubscribed bool `json:"is_subscribed" example:"true"` + SubsCount int `json:"subscribers" example:"23"` +} + +//easyjson:json +type ProfileInfo struct { + ID int `json:"id" example:"1"` + Username string `json:"username" example:"baobab"` + Avatar string `json:"avatar" example:"/pic1"` + SubsCount int `json:"subscribers" example:"12"` +} diff --git a/internal/pkg/delivery/http/v1/structs/user_easyjson.go b/internal/pkg/delivery/http/v1/structs/user_easyjson.go new file mode 100644 index 0000000..e62ee17 --- /dev/null +++ b/internal/pkg/delivery/http/v1/structs/user_easyjson.go @@ -0,0 +1,221 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package structs + +import ( + json "encoding/json" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(in *jlexer.Lexer, out *UserInfo) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "id": + out.ID = int(in.Int()) + case "username": + out.Username = string(in.String()) + case "avatar": + out.Avatar = string(in.String()) + case "name": + out.Name = string(in.String()) + case "surname": + out.Surname = string(in.String()) + case "about": + out.About = string(in.String()) + case "is_subscribed": + out.IsSubscribed = bool(in.Bool()) + case "subscribers": + out.SubsCount = int(in.Int()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(out *jwriter.Writer, in UserInfo) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"id\":" + out.RawString(prefix[1:]) + out.Int(int(in.ID)) + } + { + const prefix string = ",\"username\":" + out.RawString(prefix) + out.String(string(in.Username)) + } + { + const prefix string = ",\"avatar\":" + out.RawString(prefix) + out.String(string(in.Avatar)) + } + { + const prefix string = ",\"name\":" + out.RawString(prefix) + out.String(string(in.Name)) + } + { + const prefix string = ",\"surname\":" + out.RawString(prefix) + out.String(string(in.Surname)) + } + { + const prefix string = ",\"about\":" + out.RawString(prefix) + out.String(string(in.About)) + } + { + const prefix string = ",\"is_subscribed\":" + out.RawString(prefix) + out.Bool(bool(in.IsSubscribed)) + } + { + const prefix string = ",\"subscribers\":" + out.RawString(prefix) + out.Int(int(in.SubsCount)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v UserInfo) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v UserInfo) MarshalEasyJSON(w *jwriter.Writer) { + easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *UserInfo) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *UserInfo) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs(l, v) +} +func easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(in *jlexer.Lexer, out *ProfileInfo) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "id": + out.ID = int(in.Int()) + case "username": + out.Username = string(in.String()) + case "avatar": + out.Avatar = string(in.String()) + case "subscribers": + out.SubsCount = int(in.Int()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(out *jwriter.Writer, in ProfileInfo) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"id\":" + out.RawString(prefix[1:]) + out.Int(int(in.ID)) + } + { + const prefix string = ",\"username\":" + out.RawString(prefix) + out.String(string(in.Username)) + } + { + const prefix string = ",\"avatar\":" + out.RawString(prefix) + out.String(string(in.Avatar)) + } + { + const prefix string = ",\"subscribers\":" + out.RawString(prefix) + out.Int(int(in.SubsCount)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v ProfileInfo) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v ProfileInfo) MarshalEasyJSON(w *jwriter.Writer) { + easyjson9e1087fdEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *ProfileInfo) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *ProfileInfo) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson9e1087fdDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgDeliveryHttpV1Structs1(l, v) +} diff --git a/internal/pkg/usecase/pin/update.go b/internal/pkg/usecase/pin/update.go index fc9281c..790e9e6 100644 --- a/internal/pkg/usecase/pin/update.go +++ b/internal/pkg/usecase/pin/update.go @@ -7,11 +7,14 @@ import ( "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/repository/pin" ) +//go:generate easyjson update.go + +//easyjson:json type PinUpdateData struct { - Title *string - Description *string - Public *bool - Tags []string + Title *string `json:"title"` + Description *string `json:"description"` + Public *bool `json:"public"` + Tags []string `json:"tags"` } func (p *pinCase) EditPinByID(ctx context.Context, pinID, userID int, updateData *PinUpdateData) error { diff --git a/internal/pkg/usecase/pin/update_easyjson.go b/internal/pkg/usecase/pin/update_easyjson.go new file mode 100644 index 0000000..c3930bc --- /dev/null +++ b/internal/pkg/usecase/pin/update_easyjson.go @@ -0,0 +1,174 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package pin + +import ( + json "encoding/json" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjson2d86586fDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecasePin(in *jlexer.Lexer, out *PinUpdateData) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "title": + if in.IsNull() { + in.Skip() + out.Title = nil + } else { + if out.Title == nil { + out.Title = new(string) + } + *out.Title = string(in.String()) + } + case "description": + if in.IsNull() { + in.Skip() + out.Description = nil + } else { + if out.Description == nil { + out.Description = new(string) + } + *out.Description = string(in.String()) + } + case "public": + if in.IsNull() { + in.Skip() + out.Public = nil + } else { + if out.Public == nil { + out.Public = new(bool) + } + *out.Public = bool(in.Bool()) + } + case "tags": + if in.IsNull() { + in.Skip() + out.Tags = nil + } else { + in.Delim('[') + if out.Tags == nil { + if !in.IsDelim(']') { + out.Tags = make([]string, 0, 4) + } else { + out.Tags = []string{} + } + } else { + out.Tags = (out.Tags)[:0] + } + for !in.IsDelim(']') { + var v1 string + v1 = string(in.String()) + out.Tags = append(out.Tags, v1) + in.WantComma() + } + in.Delim(']') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson2d86586fEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecasePin(out *jwriter.Writer, in PinUpdateData) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"title\":" + out.RawString(prefix[1:]) + if in.Title == nil { + out.RawString("null") + } else { + out.String(string(*in.Title)) + } + } + { + const prefix string = ",\"description\":" + out.RawString(prefix) + if in.Description == nil { + out.RawString("null") + } else { + out.String(string(*in.Description)) + } + } + { + const prefix string = ",\"public\":" + out.RawString(prefix) + if in.Public == nil { + out.RawString("null") + } else { + out.Bool(bool(*in.Public)) + } + } + { + const prefix string = ",\"tags\":" + out.RawString(prefix) + if in.Tags == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { + out.RawString("null") + } else { + out.RawByte('[') + for v2, v3 := range in.Tags { + if v2 > 0 { + out.RawByte(',') + } + out.String(string(v3)) + } + out.RawByte(']') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v PinUpdateData) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson2d86586fEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecasePin(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v PinUpdateData) MarshalEasyJSON(w *jwriter.Writer) { + easyjson2d86586fEncodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecasePin(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *PinUpdateData) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson2d86586fDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecasePin(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *PinUpdateData) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson2d86586fDecodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecasePin(l, v) +} diff --git a/internal/pkg/usecase/user/credentials.go b/internal/pkg/usecase/user/credentials.go index c8d95d6..9e3857c 100644 --- a/internal/pkg/usecase/user/credentials.go +++ b/internal/pkg/usecase/user/credentials.go @@ -1,6 +1,9 @@ package user +//go:generate easyjson credentials.go + +//easyjson:json type UserCredentials struct { - Username string - Password string + Username string `json:"username"` + Password string `json:"password"` } diff --git a/internal/pkg/usecase/user/credentials_easyjson.go b/internal/pkg/usecase/user/credentials_easyjson.go new file mode 100644 index 0000000..d303bee --- /dev/null +++ b/internal/pkg/usecase/user/credentials_easyjson.go @@ -0,0 +1,92 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package user + +import ( + json "encoding/json" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjson5b679028DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(in *jlexer.Lexer, out *UserCredentials) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "username": + out.Username = string(in.String()) + case "password": + out.Password = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson5b679028EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(out *jwriter.Writer, in UserCredentials) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"username\":" + out.RawString(prefix[1:]) + out.String(string(in.Username)) + } + { + const prefix string = ",\"password\":" + out.RawString(prefix) + out.String(string(in.Password)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v UserCredentials) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson5b679028EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v UserCredentials) MarshalEasyJSON(w *jwriter.Writer) { + easyjson5b679028EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *UserCredentials) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson5b679028DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *UserCredentials) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson5b679028DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(l, v) +} diff --git a/internal/pkg/usecase/user/info.go b/internal/pkg/usecase/user/info.go index 1993261..b504f5f 100644 --- a/internal/pkg/usecase/user/info.go +++ b/internal/pkg/usecase/user/info.go @@ -1,10 +1,13 @@ package user +//go:generate easyjson info.go + +//easyjson:json type ProfileUpdateData struct { - Username *string - Email *string - Name *string - Surname *string + Username *string `json:"username"` + Email *string `json:"email"` + Name *string `json:"name"` + Surname *string `json:"surname"` AboutMe *string `json:"about_me"` - Password *string + Password *string `json:"password"` } diff --git a/internal/pkg/usecase/user/info_easyjson.go b/internal/pkg/usecase/user/info_easyjson.go new file mode 100644 index 0000000..af29bb5 --- /dev/null +++ b/internal/pkg/usecase/user/info_easyjson.go @@ -0,0 +1,192 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package user + +import ( + json "encoding/json" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjsonDdc53814DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(in *jlexer.Lexer, out *ProfileUpdateData) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "username": + if in.IsNull() { + in.Skip() + out.Username = nil + } else { + if out.Username == nil { + out.Username = new(string) + } + *out.Username = string(in.String()) + } + case "email": + if in.IsNull() { + in.Skip() + out.Email = nil + } else { + if out.Email == nil { + out.Email = new(string) + } + *out.Email = string(in.String()) + } + case "name": + if in.IsNull() { + in.Skip() + out.Name = nil + } else { + if out.Name == nil { + out.Name = new(string) + } + *out.Name = string(in.String()) + } + case "surname": + if in.IsNull() { + in.Skip() + out.Surname = nil + } else { + if out.Surname == nil { + out.Surname = new(string) + } + *out.Surname = string(in.String()) + } + case "about_me": + if in.IsNull() { + in.Skip() + out.AboutMe = nil + } else { + if out.AboutMe == nil { + out.AboutMe = new(string) + } + *out.AboutMe = string(in.String()) + } + case "password": + if in.IsNull() { + in.Skip() + out.Password = nil + } else { + if out.Password == nil { + out.Password = new(string) + } + *out.Password = string(in.String()) + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonDdc53814EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(out *jwriter.Writer, in ProfileUpdateData) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"username\":" + out.RawString(prefix[1:]) + if in.Username == nil { + out.RawString("null") + } else { + out.String(string(*in.Username)) + } + } + { + const prefix string = ",\"email\":" + out.RawString(prefix) + if in.Email == nil { + out.RawString("null") + } else { + out.String(string(*in.Email)) + } + } + { + const prefix string = ",\"name\":" + out.RawString(prefix) + if in.Name == nil { + out.RawString("null") + } else { + out.String(string(*in.Name)) + } + } + { + const prefix string = ",\"surname\":" + out.RawString(prefix) + if in.Surname == nil { + out.RawString("null") + } else { + out.String(string(*in.Surname)) + } + } + { + const prefix string = ",\"about_me\":" + out.RawString(prefix) + if in.AboutMe == nil { + out.RawString("null") + } else { + out.String(string(*in.AboutMe)) + } + } + { + const prefix string = ",\"password\":" + out.RawString(prefix) + if in.Password == nil { + out.RawString("null") + } else { + out.String(string(*in.Password)) + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v ProfileUpdateData) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonDdc53814EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v ProfileUpdateData) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonDdc53814EncodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *ProfileUpdateData) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonDdc53814DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *ProfileUpdateData) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonDdc53814DecodeGithubComGoParkMailRu20232ONDTeamInternalPkgUsecaseUser(l, v) +} From febce68a1a7c9e007036929ce7068baa188c83a9 Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Tue, 19 Dec 2023 14:02:00 +0300 Subject: [PATCH 14/21] dev4: removed pull request trigger for deploy workflow --- .github/workflows/deployment.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 9036f2b..7c26ded 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -4,12 +4,9 @@ on: workflow_dispatch: {} push: branches: - - TP-c01_ci-cd + - main - dev4 - pull_request: - types: [opened, edited, reopened] - branches: [main, dev4] - + jobs: build_images: runs-on: ubuntu-latest From e3d14774a2972d3fad1f849f382ce18e0a2f1497 Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Tue, 19 Dec 2023 15:53:51 +0300 Subject: [PATCH 15/21] dev4: replaced auth service host:port string with env variables, moved auth config to main.go --- cmd/app/config.go | 12 ------------ cmd/app/main.go | 7 +++++++ internal/app/app.go | 6 ++---- 3 files changed, 9 insertions(+), 16 deletions(-) delete mode 100644 cmd/app/config.go diff --git a/cmd/app/config.go b/cmd/app/config.go deleted file mode 100644 index 42f8ed3..0000000 --- a/cmd/app/config.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "os" - - "github.com/go-park-mail-ru/2023_2_OND_team/internal/app" -) - -var configFiles = app.ConfigFiles{ - ServerConfigFile: "configs/config.yml", - AddrAuthServer: os.Getenv("AUTH_SERVICE_HOST") + ":" + os.Getenv("AUTH_SERVICE_PORT"), // "localhost:8085", -} diff --git a/cmd/app/main.go b/cmd/app/main.go index 65db49a..c571572 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -4,9 +4,11 @@ import ( "context" "flag" "fmt" + "os" "github.com/go-park-mail-ru/2023_2_OND_team/internal/app" "github.com/go-park-mail-ru/2023_2_OND_team/pkg/logger" + "github.com/joho/godotenv" ) var ( @@ -27,6 +29,7 @@ var ( // @license.url http://www.apache.org/licenses/LICENSE-2.0.html func main() { + godotenv.Load() flag.Parse() ctxBase, cancel := context.WithCancel(context.Background()) defer cancel() @@ -42,5 +45,9 @@ func main() { } defer log.Sync() + configFiles := app.ConfigFiles{ + ServerConfigFile: "configs/config.yml", + AddrAuthServer: os.Getenv("AUTH_SERVICE_HOST") + ":" + os.Getenv("AUTH_SERVICE_PORT"), // "localhost:8085", + } app.Run(ctxBase, log, configFiles) } diff --git a/internal/app/app.go b/internal/app/app.go index a561039..e8c25a4 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -5,7 +5,6 @@ import ( "os" "time" - "github.com/joho/godotenv" "github.com/microcosm-cc/bluemonday" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -47,8 +46,6 @@ var _timeoutForConnPG = 5 * time.Second const uploadFiles = "upload/" func Run(ctx context.Context, log *log.Logger, cfg ConfigFiles) { - godotenv.Load() - metrics := metrics.New("pinspire") err := metrics.Registry() if err != nil { @@ -74,7 +71,8 @@ func Run(ctx context.Context, log *log.Logger, cfg ConfigFiles) { } defer connMessMS.Close() - connRealtime, err := grpc.Dial("localhost:8090", grpc.WithTransportCredentials(insecure.NewCredentials())) + // connRealtime, err := grpc.Dial("localhost:8090", grpc.WithTransportCredentials(insecure.NewCredentials())) + connRealtime, err := grpc.Dial(os.Getenv("REALTIME_SERVICE_HOST")+":"+os.Getenv("REALTIME_SERVICE_PORT"), grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Error(err.Error()) return From 0170995b7a8046e6aad0ac8dae4d73cb2267fec5 Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Tue, 19 Dec 2023 19:04:42 +0300 Subject: [PATCH 16/21] TP-87a_filtration: add filtration of pin content --- .gitignore | 1 + go.mod | 24 +- go.sum | 569 ++++++++++++++++++++++- internal/app/app.go | 17 +- internal/pkg/delivery/http/v1/pin.go | 7 +- internal/pkg/usecase/image/filtration.go | 80 ++++ internal/pkg/usecase/image/usecase.go | 30 +- internal/pkg/usecase/pin/usecase.go | 5 +- internal/pkg/usecase/user/profile.go | 2 +- 9 files changed, 700 insertions(+), 35 deletions(-) create mode 100644 internal/pkg/usecase/image/filtration.go diff --git a/.gitignore b/.gitignore index e33fae4..ad9c3ba 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,5 @@ cert/ .env redis.conf inventory +keyVision.json script* \ No newline at end of file diff --git a/go.mod b/go.mod index 9f4f39f..89b662c 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,15 @@ module github.com/go-park-mail-ru/2023_2_OND_team go 1.19 require ( + cloud.google.com/go/vision v1.2.0 + cloud.google.com/go/vision/v2 v2.7.5 github.com/IBM/sarama v1.42.1 github.com/Masterminds/squirrel v1.5.4 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/go-chi/chi/v5 v5.0.10 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.3 - github.com/google/uuid v1.3.1 + github.com/google/uuid v1.4.0 github.com/jackc/pgx/v5 v5.4.3 github.com/joho/godotenv v1.5.1 github.com/mailru/easyjson v0.7.7 @@ -27,12 +29,16 @@ require ( go.uber.org/zap v1.26.0 golang.org/x/crypto v0.14.0 golang.org/x/image v0.13.0 - google.golang.org/grpc v1.59.0 + google.golang.org/grpc v1.60.0 google.golang.org/protobuf v1.31.0 nhooyr.io/websocket v1.8.10 ) require ( + cloud.google.com/go v0.111.0 // indirect + cloud.google.com/go/compute v1.23.3 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/longrunning v0.5.4 // indirect github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect @@ -53,7 +59,11 @@ require ( github.com/go-openapi/swag v0.22.4 // indirect github.com/go-text/typesetting v0.0.0-20231013144250-6cc35dbfae7d // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -81,14 +91,20 @@ require ( github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect github.com/tdewolff/minify/v2 v2.20.5 // indirect github.com/tdewolff/parse/v2 v2.7.3 // indirect + go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect + golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/net v0.17.0 // indirect + golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/sync v0.4.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/api v0.149.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect star-tex.org/x/tex v0.4.0 // indirect diff --git a/go.sum b/go.sum index 1ec2c4a..12a2086 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,67 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM= +cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg= +cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/vision v1.2.0 h1:/CsSTkbmO9HC8iQpxbK8ATms3OQaX3YQUeTMGCxlaK4= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.7.5 h1:T/ujUghvEaTb+YnFY/jiYwVAkMbIC8EieK0CJo6B4vg= +cloud.google.com/go/vision/v2 v2.7.5/go.mod h1:GcviprJLFfK9OLf0z8Gm6lQb6ZFUulvpZws+mm6yPLM= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= git.sr.ht/~sbinet/gg v0.5.0 h1:6V43j30HM623V329xA9Ntq+WJrMjDxRjuAB1LFWF5m8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f h1:l7moT9o/v/9acCWA64Yz/HDLqjcRTvc0noQACi4MsJw= github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f/go.mod h1:vIOkSdX3NDCPwgu8FIuTat2zDF0FPXXQ0RYFRy+oQic= github.com/IBM/sarama v1.42.1 h1:wugyWa15TDEHh2kvq2gAy1IHLjEjuYOYgXz/ruC/OSQ= @@ -8,9 +70,9 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -26,8 +88,23 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -44,16 +121,30 @@ github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4A github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-fonts/latin-modern v0.3.1 h1:/cT8A7uavYKvglYXvrdDw4oS5ZLkcOU22fa2HJ1/JVM= github.com/go-fonts/latin-modern v0.3.1/go.mod h1:ysEQXnuT/sCDOAONxC7ImeEDVINbltClhasMAqEtRK0= github.com/go-fonts/liberation v0.3.1 h1:9RPT2NhUpxQ7ukUvz3jeUckmN42T9D9TpjtQcqK/ceM= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gorp/gorp v2.0.0+incompatible h1:dIQPsBtl6/H1MjVseWuWPXa7ET4p6Dve4j3Hg+UjqYw= github.com/go-gorp/gorp v2.0.0+incompatible/go.mod h1:7IfkAQnO7jfT/9IQ3R9wL1dFhukN6aQxzKTHnkxzA/E= github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9 h1:NxXI5pTAtpEaU49bpLpQoDsu1zrteW/vxzTz8Cd2UAs= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= @@ -75,22 +166,97 @@ github.com/go-text/typesetting v0.0.0-20231013144250-6cc35dbfae7d/go.mod h1:evDB github.com/go-text/typesetting-utils v0.0.0-20230616150549-2a7df14b6a22 h1:LBQTFxP2MfsyEDqSKmUBZaDuDHN1vpqDyOZjcqS7MYI= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +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.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +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/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/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.4.1/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.1/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.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 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-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -98,6 +264,10 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9 github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 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/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= @@ -122,9 +292,8 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= @@ -151,9 +320,6 @@ github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvls github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pashagolub/pgxmock/v2 v2.12.0 h1:IVRmQtVFNCoq7NOZ+PdfvB6fwnLJmEuWDhnc3yrDxBs= github.com/pashagolub/pgxmock/v2 v2.12.0/go.mod h1:D3YslkN/nJ4+umVqWmbwfSXugJIjPMChkGBG47OJpNw= @@ -164,6 +330,7 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= @@ -176,17 +343,20 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5X github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg= github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 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.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.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -209,8 +379,26 @@ github.com/tdewolff/parse/v2 v2.7.3/go.mod h1:9p2qMIHpjRSTr1qnFxQr+igogyTUTlwvf9 github.com/tdewolff/test v1.0.10/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52 h1:gAQliwn+zJrkjAHVcBEYW/RFvd2St4yYimisvozAYlA= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/config v1.4.0 h1:upnMPpMm6WlbZtXoasNkK4f0FhxwS+W4Iqz5oNznehQ= go.uber.org/config v1.4.0/go.mod h1:aCyrMHmUAc/s2h9sv1koP84M9ZF/4K+g2oleyESO/Ig= @@ -223,47 +411,180 @@ go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg= golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= +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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +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-20190108225652-1e06a53dbb7e/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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/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-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +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-20190227155943-e225da77a7e6/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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20201207232520-09787c993a3a/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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/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-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -272,23 +593,76 @@ golang.org/x/sys v0.13.0/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/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.5/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/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/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-20191104232314-dc038396d1f0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= @@ -297,12 +671,163 @@ 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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/plot v0.14.0 h1:+LBDVFYwFe4LHhdP8coW6296MBEY4nQ+Y4vuUpJopcE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.149.0 h1:b2CqT6kG+zqJIVKRQ3ELJVLN1PwHZ6DJ3dW8yl82rgY= +google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= +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.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 h1:YJ5pD9rF8o9Qtta0Cmy9rdBwkSjrTCT6XTiUQVOtIos= +google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY= +google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3 h1:EWIeHfGuUf00zrVZGEgYFxok7plSAXBGcH7NNdMAWvA= +google.golang.org/genproto/googleapis/api v0.0.0-20231211222908-989df2bf70f3/go.mod h1:k2dtGpRrbsSyKcNPKKI5sstZkrNCZwpU/ns96JoHbGg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3 h1:kzJAXnzZoFbe5bhZd4zjUuHos/I31yH4thfMb/13oVY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k= +google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +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.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -312,6 +837,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -319,8 +845,17 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/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= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= star-tex.org/x/tex v0.4.0 h1:AXUwgpnHLCxZUWW3qrmjv6ezNhH3PjUVBuLLejz2cgU= star-tex.org/x/tex v0.4.0/go.mod h1:w91ycsU/DkkCr7GWr60GPWqp3gn2U+6VX71T0o8k8qE= diff --git a/internal/app/app.go b/internal/app/app.go index e8c25a4..1e22e8c 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -9,6 +9,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + vision "cloud.google.com/go/vision/v2/apiv1" authProto "github.com/go-park-mail-ru/2023_2_OND_team/internal/api/auth" "github.com/go-park-mail-ru/2023_2_OND_team/internal/api/messenger" rt "github.com/go-park-mail-ru/2023_2_OND_team/internal/api/realtime" @@ -41,7 +42,10 @@ import ( log "github.com/go-park-mail-ru/2023_2_OND_team/pkg/logger" ) -var _timeoutForConnPG = 5 * time.Second +var ( + _timeoutForConnPG = 5 * time.Second + timeoutCloudVisionAPI = 10 * time.Second +) const uploadFiles = "upload/" @@ -83,7 +87,16 @@ func Run(ctx context.Context, log *log.Logger, cfg ConfigFiles) { commentRepository := commentRepo.NewCommentRepoPG(pool) - imgCase := image.New(log, imgRepo.NewImageRepoFS(uploadFiles)) + os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "keyVision.json") + visionCtx, cancel := context.WithTimeout(ctx, timeoutCloudVisionAPI) + defer cancel() + visionClient, err := vision.NewImageAnnotatorClient(visionCtx) + if err != nil { + log.Error(err.Error()) + return + } + + imgCase := image.New(log, imgRepo.NewImageRepoFS(uploadFiles), visionClient) messageCase := message.New(log, messenger.NewMessengerClient(connMessMS), chat.New(realtime.NewRealTimeChatClient(rtClient), log)) pinCase := pin.New(log, imgCase, pinRepo.NewPinRepoPG(pool)) diff --git a/internal/pkg/delivery/http/v1/pin.go b/internal/pkg/delivery/http/v1/pin.go index 19b2831..a0868b3 100644 --- a/internal/pkg/delivery/http/v1/pin.go +++ b/internal/pkg/delivery/http/v1/pin.go @@ -11,6 +11,7 @@ import ( entity "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/entity/pin" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/entity/user" "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/middleware/auth" + img "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/usecase/image" usecase "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/usecase/pin" ) @@ -73,7 +74,11 @@ func (h *HandlerHTTP) CreateNewPin(w http.ResponseWriter, r *http.Request) { err = h.pinCase.CreateNewPin(r.Context(), newPin, mime.Header.Get("Content-Type"), mime.Size, picture) if err != nil { logger.Error(err.Error()) - err = responseError(w, "add_pin", "failed to create pin") + if err == img.ErrExplicitImage { + err = responseError(w, "explicit_pin", err.Error()) + } else { + err = responseError(w, "add_pin", "failed to create pin") + } } else { err = responseOk(http.StatusCreated, w, "pin successfully created", nil) } diff --git a/internal/pkg/usecase/image/filtration.go b/internal/pkg/usecase/image/filtration.go new file mode 100644 index 0000000..856cfa7 --- /dev/null +++ b/internal/pkg/usecase/image/filtration.go @@ -0,0 +1,80 @@ +package image + +import ( + "context" + "errors" + "strings" + + pb "cloud.google.com/go/vision/v2/apiv1/visionpb" +) + +var ( + maxAnnotationsNumber int32 = 15 + explicitLabels = []string{"goose", "duck"} + ErrExplicitImage = errors.New("Image content doesn't comply with service policy") +) + +func CheckAnnotations(annotation *pb.SafeSearchAnnotation) bool { + if annotation.GetAdult() >= pb.Likelihood_LIKELY || + annotation.GetMedical() >= pb.Likelihood_LIKELY || + annotation.GetRacy() >= pb.Likelihood_LIKELY || + annotation.GetViolence() >= pb.Likelihood_LIKELY || + annotation.GetSpoof() >= pb.Likelihood_LIKELY { + return true + } + return false +} + +func GetImageLabels(annotations []*pb.EntityAnnotation) []string { + imgLabels := make([]string, 0, len(annotations)) + for _, label := range annotations { + imgLabels = append(imgLabels, label.GetDescription()) + } + return imgLabels +} + +func CheckCertainLabels(explicitLabels, imgLabels []string) bool { + for _, label := range explicitLabels { + if HasExplicitLabel(label, imgLabels) { + return true + } + } + return false +} + +func HasExplicitLabel(explicitLabel string, imgLabels []string) bool { + for _, label := range imgLabels { + if strings.Contains(strings.ToLower(label), strings.ToLower(explicitLabel)) { + return true + } + } + return false +} + +func CheckExplicit(resp *pb.AnnotateImageResponse, explicitLabels []string) error { + if CheckCertainLabels(explicitLabels, GetImageLabels(resp.GetLabelAnnotations())) || + CheckAnnotations(resp.GetSafeSearchAnnotation()) { + return ErrExplicitImage + } + return nil +} + +func (img *imageCase) FilterImage(ctx context.Context, imgBytes []byte, explicitLabels []string) error { + req := &pb.BatchAnnotateImagesRequest{ + Requests: []*pb.AnnotateImageRequest{ + { + Image: &pb.Image{Content: imgBytes}, + Features: []*pb.Feature{ + {Type: pb.Feature_LABEL_DETECTION, MaxResults: maxAnnotationsNumber}, + {Type: pb.Feature_SAFE_SEARCH_DETECTION, MaxResults: maxAnnotationsNumber}, + }, + }, + }, + } + resp, err := img.visionClient.BatchAnnotateImages(ctx, req) + if err != nil { + return err + } + + return CheckExplicit(resp.GetResponses()[0], explicitLabels) +} diff --git a/internal/pkg/usecase/image/usecase.go b/internal/pkg/usecase/image/usecase.go index 799ed62..100d106 100644 --- a/internal/pkg/usecase/image/usecase.go +++ b/internal/pkg/usecase/image/usecase.go @@ -2,10 +2,12 @@ package image import ( "bytes" + "context" "errors" "fmt" "io" + vision "cloud.google.com/go/vision/v2/apiv1" repo "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/repository/image" log "github.com/go-park-mail-ru/2023_2_OND_team/pkg/logger" valid "github.com/go-park-mail-ru/2023_2_OND_team/pkg/validator/image" @@ -14,33 +16,43 @@ import ( const PrefixURLImage = "https://pinspire.online:8081/" -var ErrInvalidImage = errors.New("invalid images") -var ErrUploadFile = errors.New("file upload failed") +var ( + ErrInvalidImage = errors.New("invalid images") + ErrUploadFile = errors.New("file upload failed") +) //go:generate mockgen -destination=./mock/image_mock.go -package=mock -source=usecase.go Usecase type Usecase interface { - UploadImage(path string, mimeType string, size int64, image io.Reader, check check.CheckSize) (string, error) + UploadImage(ctx context.Context, path string, mimeType string, size int64, image io.Reader, check check.CheckSize) (string, error) } type imageCase struct { - log *log.Logger - repo repo.Repository + log *log.Logger + repo repo.Repository + visionClient *vision.ImageAnnotatorClient } -func New(log *log.Logger, repo repo.Repository) *imageCase { - return &imageCase{log, repo} +func New(log *log.Logger, repo repo.Repository, visionClient *vision.ImageAnnotatorClient) *imageCase { + return &imageCase{log, repo, visionClient} } -func (img *imageCase) UploadImage(path string, mimeType string, size int64, image io.Reader, check check.CheckSize) (string, error) { +func (img *imageCase) UploadImage(ctx context.Context, path string, mimeType string, size int64, image io.Reader, check check.CheckSize) (string, error) { buf := bytes.NewBuffer(nil) extension, ok := valid.IsValidImage(io.TeeReader(image, buf), mimeType, check) if !ok { return "", ErrInvalidImage } - io.Copy(buf, image) + err := img.FilterImage(ctx, buf.Bytes(), explicitLabels) + if err != nil { + if err == ErrExplicitImage { + return "", err + } + return "", fmt.Errorf("upload image: %w", err) + } + filename, written, err := img.repo.SaveImage(path, extension, buf) if err != nil { return "", fmt.Errorf("upload image: %w", err) diff --git a/internal/pkg/usecase/pin/usecase.go b/internal/pkg/usecase/pin/usecase.go index 3a23401..f288769 100644 --- a/internal/pkg/usecase/pin/usecase.go +++ b/internal/pkg/usecase/pin/usecase.go @@ -46,8 +46,11 @@ func New(log *log.Logger, imgCase image.Usecase, repo repo.Repository) *pinCase } func (p *pinCase) CreateNewPin(ctx context.Context, pin *entity.Pin, mimeTypePicture string, sizePicture int64, picture io.Reader) error { - picturePin, err := p.UploadImage("pins/", mimeTypePicture, sizePicture, picture, check.BothSidesFallIntoRange(100, 6000)) + picturePin, err := p.UploadImage(ctx, "pins/", mimeTypePicture, sizePicture, picture, check.BothSidesFallIntoRange(100, 6000)) if err != nil { + if err == image.ErrExplicitImage { + return err + } return fmt.Errorf("uploading an avatar when creating pin: %w", err) } pin.Picture = picturePin diff --git a/internal/pkg/usecase/user/profile.go b/internal/pkg/usecase/user/profile.go index 1a5d1e4..414c4a0 100644 --- a/internal/pkg/usecase/user/profile.go +++ b/internal/pkg/usecase/user/profile.go @@ -16,7 +16,7 @@ import ( var ErrBadBody = errors.New("bad body avatar") func (u *userCase) UpdateUserAvatar(ctx context.Context, userID int, mimeTypeAvatar string, sizeAvatar int64, avatar io.Reader) error { - avatarProfile, err := u.UploadImage("avatars/", mimeTypeAvatar, sizeAvatar, avatar, check.BothSidesFallIntoRange(200, 1800)) + avatarProfile, err := u.UploadImage(ctx, "avatars/", mimeTypeAvatar, sizeAvatar, avatar, check.BothSidesFallIntoRange(200, 1800)) if err != nil { return fmt.Errorf("uploading an avatar when updating avatar profile: %w", err) } From ff133463b44d49e28407382d1076021a027d7970 Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Tue, 19 Dec 2023 19:06:24 +0300 Subject: [PATCH 17/21] TP-87a_filtration: add task with cloud api token provision, add '2023_2_OND_team' folder to dest --- configs/playbook.yml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/configs/playbook.yml b/configs/playbook.yml index 2daa6b2..c43f92a 100644 --- a/configs/playbook.yml +++ b/configs/playbook.yml @@ -5,8 +5,22 @@ - name: "Provide .env file" copy: src: ../.env - dest: /home/ond_team/go/src/github.com/go-park-mail-ru/ci-cd/.env + dest: /home/ond_team/go/src/github.com/go-park-mail-ru/{{ item }}/.env + with_items: + - ci-cd + - 2023_2_OND_team - name: "Provide redis config" copy: src: ../redis.conf - dest: /home/ond_team/go/src/github.com/go-park-mail-ru/ci-cd/redis.conf + dest: /home/ond_team/go/src/github.com/go-park-mail-ru/{{ item }}/redis.conf + with_items: + - ci-cd + - 2023_2_OND_team + - name: "Provide key for Google Cloud Vision API" + copy: + src: ../keyVision.json + dest: /home/ond_team/go/src/github.com/go-park-mail-ru/{{ item }}/keyVision.json + with_items: + - ci-cd + - 2023_2_OND_team + From 63118112f0e643caa9143112bbd577ce028a5002 Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Wed, 20 Dec 2023 11:19:09 +0300 Subject: [PATCH 18/21] dev4: replaced google vision client with image filter interface --- internal/app/app.go | 2 +- internal/pkg/usecase/image/filtration.go | 17 +++++++++++++++-- internal/pkg/usecase/image/usecase.go | 13 ++++++------- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index 1e22e8c..87ea2f6 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -96,7 +96,7 @@ func Run(ctx context.Context, log *log.Logger, cfg ConfigFiles) { return } - imgCase := image.New(log, imgRepo.NewImageRepoFS(uploadFiles), visionClient) + imgCase := image.New(log, imgRepo.NewImageRepoFS(uploadFiles), image.NewFilter(visionClient)) messageCase := message.New(log, messenger.NewMessengerClient(connMessMS), chat.New(realtime.NewRealTimeChatClient(rtClient), log)) pinCase := pin.New(log, imgCase, pinRepo.NewPinRepoPG(pool)) diff --git a/internal/pkg/usecase/image/filtration.go b/internal/pkg/usecase/image/filtration.go index 856cfa7..8b73710 100644 --- a/internal/pkg/usecase/image/filtration.go +++ b/internal/pkg/usecase/image/filtration.go @@ -5,6 +5,7 @@ import ( "errors" "strings" + vision "cloud.google.com/go/vision/v2/apiv1" pb "cloud.google.com/go/vision/v2/apiv1/visionpb" ) @@ -14,6 +15,18 @@ var ( ErrExplicitImage = errors.New("Image content doesn't comply with service policy") ) +type ImageFilter interface { + Filter(ctx context.Context, imgBytes []byte, explicitLabels []string) error +} + +type googleVision struct { + visionClient *vision.ImageAnnotatorClient +} + +func NewFilter(client *vision.ImageAnnotatorClient) *googleVision { + return &googleVision{client} +} + func CheckAnnotations(annotation *pb.SafeSearchAnnotation) bool { if annotation.GetAdult() >= pb.Likelihood_LIKELY || annotation.GetMedical() >= pb.Likelihood_LIKELY || @@ -59,7 +72,7 @@ func CheckExplicit(resp *pb.AnnotateImageResponse, explicitLabels []string) erro return nil } -func (img *imageCase) FilterImage(ctx context.Context, imgBytes []byte, explicitLabels []string) error { +func (vision *googleVision) Filter(ctx context.Context, imgBytes []byte, explicitLabels []string) error { req := &pb.BatchAnnotateImagesRequest{ Requests: []*pb.AnnotateImageRequest{ { @@ -71,7 +84,7 @@ func (img *imageCase) FilterImage(ctx context.Context, imgBytes []byte, explicit }, }, } - resp, err := img.visionClient.BatchAnnotateImages(ctx, req) + resp, err := vision.visionClient.BatchAnnotateImages(ctx, req) if err != nil { return err } diff --git a/internal/pkg/usecase/image/usecase.go b/internal/pkg/usecase/image/usecase.go index 100d106..5ace111 100644 --- a/internal/pkg/usecase/image/usecase.go +++ b/internal/pkg/usecase/image/usecase.go @@ -7,7 +7,6 @@ import ( "fmt" "io" - vision "cloud.google.com/go/vision/v2/apiv1" repo "github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/repository/image" log "github.com/go-park-mail-ru/2023_2_OND_team/pkg/logger" valid "github.com/go-park-mail-ru/2023_2_OND_team/pkg/validator/image" @@ -27,13 +26,13 @@ type Usecase interface { } type imageCase struct { - log *log.Logger - repo repo.Repository - visionClient *vision.ImageAnnotatorClient + log *log.Logger + repo repo.Repository + filter ImageFilter } -func New(log *log.Logger, repo repo.Repository, visionClient *vision.ImageAnnotatorClient) *imageCase { - return &imageCase{log, repo, visionClient} +func New(log *log.Logger, repo repo.Repository, filter ImageFilter) *imageCase { + return &imageCase{log, repo, filter} } func (img *imageCase) UploadImage(ctx context.Context, path string, mimeType string, size int64, image io.Reader, check check.CheckSize) (string, error) { @@ -45,7 +44,7 @@ func (img *imageCase) UploadImage(ctx context.Context, path string, mimeType str } io.Copy(buf, image) - err := img.FilterImage(ctx, buf.Bytes(), explicitLabels) + err := img.filter.Filter(ctx, buf.Bytes(), explicitLabels) if err != nil { if err == ErrExplicitImage { return "", err From e4dc4784a6f91446c365d923de6f26dae8787a65 Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Wed, 20 Dec 2023 11:27:37 +0300 Subject: [PATCH 19/21] de4: changed deployment branch, add cloud api token to the .env file --- .github/workflows/deployment.yml | 2 +- configs/playbook.yml | 8 -------- internal/app/app.go | 14 ++++++++++++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 7c26ded..97709e8 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -42,7 +42,7 @@ jobs: key: ${{ secrets.PRIVATE_KEY }} script: | cd ${{ secrets.PINSPIRE_BACKEND_PATH }} - sudo git switch TP-c01_ci-cd + sudo git switch dev4 sudo git pull - name: deploy application uses: appleboy/ssh-action@master diff --git a/configs/playbook.yml b/configs/playbook.yml index c43f92a..2e134dc 100644 --- a/configs/playbook.yml +++ b/configs/playbook.yml @@ -16,11 +16,3 @@ with_items: - ci-cd - 2023_2_OND_team - - name: "Provide key for Google Cloud Vision API" - copy: - src: ../keyVision.json - dest: /home/ond_team/go/src/github.com/go-park-mail-ru/{{ item }}/keyVision.json - with_items: - - ci-cd - - 2023_2_OND_team - diff --git a/internal/app/app.go b/internal/app/app.go index 87ea2f6..5f69dac 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -2,10 +2,13 @@ package app import ( "context" + "encoding/base64" + "fmt" "os" "time" "github.com/microcosm-cc/bluemonday" + "google.golang.org/api/option" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -87,10 +90,17 @@ func Run(ctx context.Context, log *log.Logger, cfg ConfigFiles) { commentRepository := commentRepo.NewCommentRepoPG(pool) - os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "keyVision.json") visionCtx, cancel := context.WithTimeout(ctx, timeoutCloudVisionAPI) defer cancel() - visionClient, err := vision.NewImageAnnotatorClient(visionCtx) + + token, err := base64.StdEncoding.DecodeString(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")) + fmt.Println(string(token)) + if err != nil { + log.Error(err.Error()) + return + } + + visionClient, err := vision.NewImageAnnotatorClient(visionCtx, option.WithCredentialsJSON(token)) if err != nil { log.Error(err.Error()) return From cae7718e5d6ac7014fe47d7d8719612448cb40e9 Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Wed, 20 Dec 2023 13:49:26 +0300 Subject: [PATCH 20/21] dev4: add images volume for main service container --- deployments/docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/deployments/docker-compose.yml b/deployments/docker-compose.yml index 44d21c6..dc87d2d 100644 --- a/deployments/docker-compose.yml +++ b/deployments/docker-compose.yml @@ -49,6 +49,7 @@ services: volumes: - '/home/ond_team/cert/fullchain.pem:/home/ond_team/cert/fullchain.pem:ro' - '/home/ond_team/cert/privkey.pem:/home/ond_team/cert/privkey.pem:ro' + - '/home/ond_team/go/src/github.com/go-park-mail-ru/ci-cd/upload:/upload' depends_on: postgres: condition: 'service_healthy' From e71947b9215c31086230a0e62118efb3fb0b807a Mon Sep 17 00:00:00 2001 From: wonderf00l Date: Wed, 20 Dec 2023 15:58:48 +0300 Subject: [PATCH 21/21] dev4: changed makefile variable, included all branches in CI --- .github/workflows/ci.yml | 1 - Makefile | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0f2a3f..863258e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,6 @@ on: push: {} pull_request: types: [opened, edited, reopened] - branches: [main, dev4] jobs: test: diff --git a/Makefile b/Makefile index ee03e17..f054d18 100644 --- a/Makefile +++ b/Makefile @@ -8,8 +8,7 @@ COV_OUT=coverage.out COV_HTML=coverage.html CURRCOVER=github.com/go-park-mail-ru/2023_2_OND_team/internal/pkg/delivery/http/v1 -PROJECT_DIR = $(shell pwd) -PROJECT_BIN = $(PROJECT_DIR)/bin +PROJECT_BIN = $(CURDIR)/bin $(shell [ -f bin ] || mkdir -p $(PROJECT_BIN)) GOLANGCI_LINT = $(PROJECT_BIN)/golangci-lint