diff --git a/.github/actions/cleanup-stale/action.yaml b/.github/actions/cleanup-stale/action.yaml index 5df2e9b24..a82536d73 100644 --- a/.github/actions/cleanup-stale/action.yaml +++ b/.github/actions/cleanup-stale/action.yaml @@ -44,7 +44,7 @@ runs: password: ${{ inputs.token }} - name: Delete untagged images with no dependency - uses: Chizkiyahu/delete-untagged-ghcr-action@v3 + uses: Chizkiyahu/delete-untagged-ghcr-action@v4 with: repository: ${{ github.repository }} repository_owner: ${{ github.repository_owner }} diff --git a/.github/workflows/build-publish.yaml b/.github/workflows/build-publish.yaml index 05705ce92..e28eaa7df 100644 --- a/.github/workflows/build-publish.yaml +++ b/.github/workflows/build-publish.yaml @@ -109,9 +109,6 @@ jobs: - name: cert-tool directory: tools/cert-tool file: tools/cert-tool/Dockerfile - - name: nats-server-config-reloader - directory: tools/nats-server-config-reloader - file: tools/nats-server-config-reloader/Dockerfile - name: snapshot-service directory: snapshot-service file: .tmp/docker/snapshot-service/Dockerfile diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 844e49223..da7cc5758 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -12,8 +12,8 @@ jobs: matrix: include: # check support for oldest supported golang version - - name: go1.20 - go-version: "~1.20" + - name: go1.22 + go-version: "~1.22" runs-on: ubuntu-latest steps: - name: Checkout @@ -22,7 +22,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: ${{ matrix.go-version || '^1.20' }} + go-version: ${{ matrix.go-version || '^1.22' }} check-latest: true - run: | diff --git a/.github/workflows/checkFormat.yml b/.github/workflows/checkFormat.yml index d81d5976e..a6226037e 100644 --- a/.github/workflows/checkFormat.yml +++ b/.github/workflows/checkFormat.yml @@ -22,7 +22,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-go@v5 with: - go-version: "^1.20" # The Go version to download (if necessary) and use. + go-version: "^1.22" # The Go version to download (if necessary) and use. check-latest: true - name: Check formatting diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 9c80297ec..6a7b33e10 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -24,13 +24,13 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: "^1.20" # The Go version to download (if necessary) and use. + go-version: "^1.22" # The Go version to download (if necessary) and use. check-latest: true cache: false - run: go version - name: golangci-lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v5 with: version: latest args: --timeout=5m diff --git a/.github/workflows/measureMemory.yml b/.github/workflows/measureMemory.yml index 201e0604b..f011846ef 100644 --- a/.github/workflows/measureMemory.yml +++ b/.github/workflows/measureMemory.yml @@ -288,7 +288,7 @@ jobs: - name: Resolve database id: db run: | - if [ "${{ github.event_name != 'workflow_dispatch' || inputs.cql }}" == "true" ]; then + if [ "${{ github.event_name == 'workflow_dispatch' && inputs.cql }}" == "true" ]; then echo "name=cqldb" >> $GITHUB_OUTPUT else echo "name=mongodb" >> $GITHUB_OUTPUT diff --git a/.github/workflows/staticAnalysis.yml b/.github/workflows/staticAnalysis.yml index e32c75abf..8acc7d31f 100644 --- a/.github/workflows/staticAnalysis.yml +++ b/.github/workflows/staticAnalysis.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: "^1.20" # The Go version to download (if necessary) and use. + go-version: "^1.22" # The Go version to download (if necessary) and use. check-latest: true - run: go version diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 418962e3c..5c7139d79 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -98,6 +98,14 @@ jobs: with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + # login to ghcr.io so we can download device/bridge-device package + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Run a test run: | make ${{ matrix.cmd }} TEST_CHECK_RACE=${{ matrix.checkRace }} \ diff --git a/.golangci.yml b/.golangci.yml index 6373304e8..9a83c0b0a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,17 +1,8 @@ -run: - skip-dirs: - - dependency - - http-gateway/grpc-websocket-proxy - skip-dirs-use-default: false - linters-settings: - gocyclo: - min-complexity: 15 - govet: - # check-shadowing: true - check-shadowing: false exhaustive: default-signifies-exhaustive: true + gocyclo: + min-complexity: 15 gomodguard: blocked: modules: @@ -21,90 +12,116 @@ linters-settings: gosec: excludes: - G402 + govet: + enable: + - nilness + - shadow stylecheck: - go: "1.20" checks: ["all", "-ST1003"] linters: enable: + - asasalint # Check for pass []any as any in variadic func(...any) - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers - bidichk # Checks for dangerous unicode character sequences - # - bodyclose # checks whether HTTP response body is closed successfully - # - contextcheck # check the function whether use a non-inherited context - - decorder # check declaration order and count of types, constants, variables and functions - # - depguard # Go linter that checks if package imports are in a list of acceptable packages + - bodyclose # Checks whether HTTP response body is closed successfully + # - copyloopvar # Detects places where loop variables are copied + - decorder # Check declaration order and count of types, constants, variables and functions - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) - # - dupl # Tool for code clone detection - - durationcheck # check for two durations multiplied together + - dupl # Tool for code clone detection + - dupword # A linter that checks for duplicate words in the source code (usually miswritten) + - durationcheck # Check for two durations multiplied together - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases - errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted. - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. - # - exhaustive # check exhaustiveness of enum switch statements + - execinquery # Execinquery is a linter about query string checker in Query function which reads your Go src files and warning it finds. - exportloopref # checks for pointers to enclosing loop variables - # - forbidigo # Forbids identifiers # - forcetypeassert # finds forced type assertions - gci # Gci control golang package import order and make it always deterministic. - # - gochecknoglobals # Checks that no globals are present in Go code - # - gochecknoinits # Checks that no init functions are present in Go code - # - gocognit # Computes and checks the cognitive complexity of functions + - gocheckcompilerdirectives # Checks that go compiler directive comments (//go:) are valid. + - gocognit # Computes and checks the cognitive complexity of functions - goconst # Finds repeated strings that could be replaced by a constant - gocritic # The most opinionated Go source code linter - # - gocyclo # Computes and checks the cyclomatic complexity of functions + - gocyclo # Computes and checks the cyclomatic complexity of functions # - godox # Tool for detection of FIXME, TODO and other comment keywords # - goerr113 # Golang linter to check the errors handling expressions - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification - gofumpt # Gofumpt checks whether code was gofumpt-ed. - goheader # Checks is file header matches to pattern - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports - - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. + # - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. - goprintffuncname # Checks that printf-like functions are named with `f` at the end - gosec # Inspects source code for security problems + - gosmopolitan # Report certain i18n/l10n anti-patterns in your Go codebase - gosimple # Linter for Go source code that specializes in simplifying a code - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string - - grouper # An analyzer to analyze expression groups. + - grouper # An analyzer to analyze expression groups - importas # Enforces consistent import aliases - ineffassign # Detects when assignments to existing variables are not used + # - intrange # Intrange is a linter to find places where for loops could make use of an integer range + - loggercheck # Checks key value pairs for common logger libraries (kitlog,klog,logr,zap). + - mirror # Reports wrong mirror patterns of bytes/strings usage - misspell # Finds commonly misspelled English words in comments - nakedret # Finds naked returns in functions greater than a specified function length + - nestif # Reports deeply nested if statements - nilerr # Finds the code that returns nil even if it checks that the error is not nil. # - nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. # - noctx # noctx finds sending http request without context.Context - nolintlint # Reports ill-formed or insufficient nolint directives - # - paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test + - nosprintfhostport # Checks for misuse of Sprintf to construct a host with port in a URL + - perfsprint # Checks that fmt.Sprintf can be replaced with a faster alternative. + - prealloc # Finds slice declarations that could potentially be preallocated - predeclared # find code that shadows one of Go's predeclared identifiers + - protogetter # Reports direct reads from proto message fields when getters should be used. - revive # golint replacement, finds style mistakes + - reassign # Checks that package variables are not reassigned + - sloglint # Ensure consistent code style when using log/slog + - spancheck # Checks for mistakes with OpenTelemetry/Census spans - staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks - stylecheck # Stylecheck is a replacement for golint - # - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 - # - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes + - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 + - testifylint # Checks usage of github.com/stretchr/testify. + - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code - unconvert # Remove unnecessary type conversions - unparam # Reports unused function parameters - unused # Checks Go code for unused constants, variables, functions and types - # - wastedassign # wastedassign finds wasted assignment statements + - usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library. + - wastedassign # wastedassign finds wasted assignment statements - whitespace # Tool for detection of leading and trailing whitespace disable: - containedctx # containedctx is a linter that detects struct contained context.Context field + - contextcheck # check the function whether use a non-inherited context - cyclop # checks function and package cyclomatic complexity + - depguard # Go linter that checks if package imports are in a list of acceptable packages + - exhaustive # Check exhaustiveness of enum switch statements - exhaustivestruct # Checks if all struct's fields are initialized + - exhaustruct # Checks if all structure fields are initialized. + - forbidigo # Forbids identifiers - funlen # Tool for detection of long functions + - gochecknoglobals # Checks that no globals are present in Go code + - gochecknoinits # Checks that no init functions are present in Go code - godot # Check if comments end in a period - gomnd # An analyzer to detect magic numbers. - ifshort # Checks that your code uses short syntax for if-statements whenever possible + - inamedparam # Reports interfaces with unnamed method parameters. + - interfacebloat # A linter that checks the number of methods inside an interface - ireturn # Accept Interfaces, Return Concrete Types - lll # Reports long lines - maintidx # maintidx measures the maintainability index of each function. - makezero # Finds slice declarations with non-zero initial length - maligned # Tool to detect Go structs that would take less memory if their fields were sorted - - nestif # Reports deeply nested if statements - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity - - prealloc # Finds slice declarations that could potentially be preallocated + - nonamedreturns # Reports all named returns + - paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test - promlinter # Check Prometheus metrics naming via promlint - rowserrcheck # checks whether Err of rows is checked successfully - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. + - tagalign # Check that struct tags are well aligned. - tagliatelle # Checks the struct tags. + - testableexamples # linter checks if examples are testable (have an expected output) - testpackage # linter that makes you use a separate _test package - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers - varnamelen # checks that the length of a variable's name matches its scope @@ -112,6 +129,12 @@ linters: - wsl # Whitespace Linter - Forces you to use empty lines! issues: + exclude-dirs: + - dependency + - http-gateway/grpc-websocket-proxy + exclude-files: + - ".*\\.pb\\.go$" + - ".*\\.pb\\.gw\\.go$" exclude-rules: - path: _test.go linters: @@ -123,10 +146,6 @@ issues: - gocognit - gocyclo - gosec - - path: tools/nats-server-config-reloader/pkg/natsreloader/natsreloader.go - text: "G404:" - linters: - - gosec - path: pkg/time/delay.go text: "G404:" linters: @@ -138,5 +157,20 @@ issues: text: "SA1019:" linters: - staticcheck + - path: grpc-gateway/client/client.go + linters: + - dupword + - path: coap-gateway/service/session.go + linters: + - dupl + - path: grpc-gateway/client/subscription.go + linters: + - dupl + - path: resource-aggregate/events/resourceLinks.*.go|resource-aggregate/client/sync.*.go|resource-aggregate/service/grpcApi.go|resource-aggregate/events/resource.*.go + linters: + - dupl # Fix found issues (if it's supported by the linter). # fix: true + +run: + go: "1.22" diff --git a/.vscode/settings.json b/.vscode/settings.json index 1eb846981..3612aa334 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -27,14 +27,17 @@ "TEST_MEMORY_COAP_GATEWAY_EXPECTED_RSS_IN_MB": "1000", "TEST_MEMORY_COAP_GATEWAY_RESOURCE_DATA_SIZE": "200", "TEST_COAP_GATEWAY_LOG_LEVEL": "info", - "TEST_COAP_GATEWAY_LOG_DUMP_BODY": "false", + "TEST_COAP_GATEWAY_LOG_DUMP_BODY": "false", "TEST_RESOURCE_AGGREGATE_LOG_LEVEL": "info", - "TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY": "false", + "TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY": "false", "TEST_GRPC_GATEWAY_LOG_LEVEL": "info", - "TEST_GRPC_GATEWAY_LOG_DUMP_BODY": "false", + "TEST_GRPC_GATEWAY_LOG_DUMP_BODY": "false", "TEST_IDENTITY_STORE_LOG_LEVEL": "info", - "TEST_IDENTITY_STORE_LOG_DUMP_BODY": "false", + "TEST_IDENTITY_STORE_LOG_DUMP_BODY": "false", "TEST_DATABASE": "mongoDB", + "TEST_BRIDGE_DEVICE_CONFIG": "${workspaceFolder}/.tmp/bridge/config-test.yaml", + // "TEST_DEVICE_NAME": "bridged-device-0", + // "TEST_DEVICE_TYPE": "bridged", // "GODEBUG": "scavtrace=1", // "TEST_COAP_GATEWAY_UDP_ENABLED": "true", // "GOMAXPROCS": 1, @@ -49,5 +52,8 @@ ], "files.watcherExclude": { "**/plgd-dev/hub/v2/**": true + }, + "[proto3]": { + "editor.formatOnSave": false } } \ No newline at end of file diff --git a/Dockerfile.test b/Dockerfile.test index 9b4d1596d..620c3a696 100644 --- a/Dockerfile.test +++ b/Dockerfile.test @@ -1,11 +1,12 @@ FROM ubuntu:22.04 AS hub-test RUN apt-get update \ && DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends build-essential ca-certificates curl git make patch sudo \ + && apt-get clean \ && curl -sSL https://get.docker.com/ | sh # apt: ca-certificates git make sudo RUN git clone https://github.com/udhos/update-golang.git \ && cd update-golang \ - && sudo RELEASE=1.20.13 ./update-golang.sh \ + && sudo RELEASE=1.22.3 ./update-golang.sh \ && ln -s /usr/local/go/bin/go /usr/bin/go WORKDIR $GOPATH/src/github.com/plgd-dev/hub COPY go.mod go.sum ./ @@ -15,9 +16,12 @@ COPY . . WORKDIR $GOPATH/src/github.com/plgd-dev/hub/tools/cert-tool RUN go build -o /usr/bin/cert-tool -WORKDIR $GOPATH/src/github.com/plgd-dev/hub +WORKDIR /usr/local/go # apt: patch -RUN ( cd /usr/local/go && patch -p1 < $GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch ) +RUN ( patch -p1 < "$GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch" ) + + +WORKDIR $GOPATH/src/github.com/plgd-dev/hub # RUN go mod tidy diff --git a/Makefile b/Makefile index ca4e2d7e0..3e5cbf8fe 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ TEST_DATABASE ?= mongodb CERT_TOOL_SIGN_ALG ?= ECDSA-SHA256 # supported values: P256, P384, P521 CERT_TOOL_ELLIPTIC_CURVE ?= P256 -CERT_TOOL_IMAGE=ghcr.io/plgd-dev/hub/cert-tool:vnext +CERT_TOOL_IMAGE = ghcr.io/plgd-dev/hub/cert-tool:vnext SUBDIRS := bundle certificate-authority cloud2cloud-connector cloud2cloud-gateway coap-gateway grpc-gateway resource-aggregate resource-directory http-gateway identity-store test/oauth-server tools/cert-tool snapshot-service .PHONY: $(SUBDIRS) push proto/generate clean build test env mongo nats certificates hub-build http-gateway-www simulators @@ -225,6 +225,64 @@ simulators: simulators/clean $(call RUN-DOCKER-DEVICE,$(DEVICE_SIMULATOR_RES_OBSERVABLE_NAME),$(DEVICE_SIMULATOR_RES_OBSERVABLE_IMG)) .PHONY: simulators +BRIDGE_DEVICE_SRC_DIR = $(WORKING_DIRECTORY)/test/bridge-device +BRIDGE_DEVICE_IMAGE = ghcr.io/plgd-dev/device/bridge-device:vnext +BRIDGE_DEVICE_NAME = bridgedev +BRIDGE_DEVICE_ID ?= 8f596b43-29c0-4147-8b40-e99268ab30f7 +BRIDGE_DEVICE_RESOURCES_PER_DEVICE ?= 3 +BRIDGE_DEVICES_COUNT ?= 3 + +define SET-BRIDGE-DEVICE-CONFIG + yq -i '.apis.coap.id = "$(BRIDGE_DEVICE_ID)"' $(1) + yq -i '.apis.coap.externalAddresses=["127.0.0.1:15683","[::1]:15683"]' $(1) + yq -i '.cloud.enabled=true' $(1) + yq -i '.cloud.cloudID="$(CLOUD_SID)"' $(1) + yq -i '.cloud.tls.caPoolPath="$(2)/certs/root_ca.crt"' $(1) + yq -i '.cloud.tls.keyPath="$(2)/certs/coap.key"' $(1) + yq -i '.cloud.tls.certPath="$(2)/certs/coap.crt"' $(1) + yq -i '.numGeneratedBridgedDevices=$(BRIDGE_DEVICES_COUNT)' $(1) + yq -i '.numResourcesPerDevice=$(BRIDGE_DEVICE_RESOURCES_PER_DEVICE)' $(1) + yq -i '.thingDescription.enabled=true' $(1) + yq -i '.thingDescription.file="$(2)/bridge/bridge-device.jsonld"' $(1) +endef + +# config-docker.yaml -> copy of configuration with paths valid inside docker container +# config-test.yaml -> copy of configuration with paths valid on host machine +simulators/bridge/env: simulators/bridge/clean certificates + mkdir -p $(WORKING_DIRECTORY)/.tmp/bridge + cp $(BRIDGE_DEVICE_SRC_DIR)/bridge-device.jsonld $(WORKING_DIRECTORY)/.tmp/bridge/ + cp $(BRIDGE_DEVICE_SRC_DIR)/config.yaml $(WORKING_DIRECTORY)/.tmp/bridge/config-docker.yaml + $(call SET-BRIDGE-DEVICE-CONFIG,$(WORKING_DIRECTORY)/.tmp/bridge/config-docker.yaml,) + cp $(BRIDGE_DEVICE_SRC_DIR)/config.yaml $(WORKING_DIRECTORY)/.tmp/bridge/config-test.yaml + $(call SET-BRIDGE-DEVICE-CONFIG,$(WORKING_DIRECTORY)/.tmp/bridge/config-test.yaml,$(WORKING_DIRECTORY)/.tmp) + +.PHONY: simulators/bridge/env + +define RUN-BRIDGE-DOCKER-DEVICE + docker pull $(BRIDGE_DEVICE_IMAGE) ; \ + docker run \ + -d \ + --name=$(BRIDGE_DEVICE_NAME) \ + --network=host \ + -v $(WORKING_DIRECTORY)/.tmp/certs:/certs \ + -v $(WORKING_DIRECTORY)/.tmp/bridge:/bridge \ + $(BRIDGE_DEVICE_IMAGE) -config /bridge/config-docker.yaml +endef + +simulators/bridge: simulators/bridge/env + $(call RUN-BRIDGE-DOCKER-DEVICE) + +.PHONY: simulators/bridge + +simulators/bridge/clean: + rm -rf $(WORKING_DIRECTORY)/.tmp/bridge || : + $(call REMOVE-DOCKER-DEVICE,$(BRIDGE_DEVICE_NAME)) + +.PHONY: simulators/bridge/clean + +simulators: simulators/bridge +simulators/clean: simulators/bridge/clean + env/test/mem: clean certificates nats mongo privateKeys scylla .PHONY: env/test/mem @@ -235,6 +293,7 @@ define RUN-DOCKER docker run \ --rm \ --network=host \ + -v $(WORKING_DIRECTORY)/.tmp/bridge:/bridge \ -v $(WORKING_DIRECTORY)/.tmp/certs:/certs \ -v $(WORKING_DIRECTORY)/.tmp/coverage:/coverage \ -v $(WORKING_DIRECTORY)/.tmp/report:/report \ @@ -253,6 +312,7 @@ define RUN-DOCKER -e TEST_OAUTH_SERVER_ID_TOKEN_PRIVATE_KEY=/privKeys/idTokenKey.pem \ -e TEST_OAUTH_SERVER_ACCESS_TOKEN_PRIVATE_KEY=/privKeys/accessTokenKey.pem \ -e TEST_HTTP_GW_WWW_ROOT=/usr/local/www \ + -e TEST_BRIDGE_DEVICE_CONFIG=/bridge/config-docker.yaml \ hub-test \ $(1) ; endef diff --git a/bundle/Dockerfile b/bundle/Dockerfile index 2721fd6e6..71ee55fb4 100644 --- a/bundle/Dockerfile +++ b/bundle/Dockerfile @@ -1,11 +1,14 @@ # syntax=docker/dockerfile:1 -FROM golang:1.20.13-alpine AS build +FROM golang:1.22.3-alpine AS build RUN apk add --no-cache curl git build-base WORKDIR $GOPATH/src/github.com/plgd-dev/hub COPY go.mod go.sum ./ RUN go mod download COPY . . -RUN ( cd /usr/local/go && patch -p1 < $GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch ) +WORKDIR /usr/local/go +RUN ( patch -p1 < "$GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch" ) +WORKDIR $GOPATH/src/github.com/plgd-dev/hub + ARG root_directory=$GOPATH/src/github.com/plgd-dev/hub ARG COMMIT_DATE @@ -17,57 +20,90 @@ ARG RELEASE_URL #coap-gateway ARG service=coap-gateway WORKDIR $root_directory/$service -RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/$service ./cmd/service +RUN go build \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o "/go/bin/$service" \ + ./cmd/service #grpc-gateway ARG service=grpc-gateway WORKDIR $root_directory/$service -RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/$service ./cmd/service +RUN go build \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o "/go/bin/$service" \ + ./cmd/service #http-gateway ARG service=http-gateway WORKDIR $root_directory/$service -RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/$service ./cmd/service +RUN go build \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o "/go/bin/$service" \ + ./cmd/service #resource-directory ARG service=resource-directory WORKDIR $root_directory/$service -RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/$service ./cmd/service +RUN go build \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o "/go/bin/$service" \ + ./cmd/service #resource-aggregate ARG service=resource-aggregate WORKDIR $root_directory/$service -RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/$service ./cmd/service +RUN go build \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o "/go/bin/$service" \ + ./cmd/service #identity-store ARG service=identity-store WORKDIR $root_directory/$service -RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/$service ./cmd/service +RUN go build \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o "/go/bin/$service" \ + ./cmd/service #certificate-authority ARG service=certificate-authority WORKDIR $root_directory/$service -RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/$service ./cmd/service +RUN go build \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o "/go/bin/$service" \ + ./cmd/service #oauth-server ARG service=oauth-server WORKDIR $root_directory/test/$service -RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/$service ./cmd/service +RUN go build \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o "/go/bin/$service" \ + ./cmd/service #cloud2cloud-gateway ARG service=cloud2cloud-gateway WORKDIR $root_directory/$service -RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/$service ./cmd/service +RUN go build \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o "/go/bin/$service" \ + ./cmd/service #cloud2cloud-connector ARG service=cloud2cloud-connector WORKDIR $root_directory/$service -RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/$service ./cmd/service +RUN go build \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o "/go/bin/$service" \ + ./cmd/service #cert-tool ARG tool=cert-tool WORKDIR $root_directory/tools/$tool -RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/$tool ./ +RUN go build \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o "/go/bin/$tool" \ + ./ #snapshot-service ARG service=snapshot-service @@ -95,18 +131,20 @@ RUN unzip ./nats.zip -d ./nats RUN cp ./nats/*/nats /go/bin/nats FROM ubuntu:22.04 AS service -RUN apt update # iproute2 -> ip utility in run.sh # netcat -> nc utility in run.sh # nginx -> nginx server in run.sh # openssl -> openssl utility in run.sh -RUN apt-get install -y --no-install-recommends ca-certificates gnupg iproute2 netcat nginx openssl wget curl sudo coreutils +RUN apt update \ + && apt-get install -y --no-install-recommends ca-certificates gnupg iproute2 netcat nginx openssl wget curl sudo coreutils \ + && apt-get clean # yq utility in run.sh RUN wget https://github.com/mikefarah/yq/releases/download/v4.6.3/yq_linux_$(dpkg --print-architecture) -O /usr/bin/yq && chmod +x /usr/bin/yq RUN wget -qO - https://pgp.mongodb.com/server-6.0.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/mongodb-6.0.gpg RUN echo "deb [ arch=$(dpkg --print-architecture) ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-6.0.list -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends mongodb-org mongodb-org-server +RUN apt update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends mongodb-org mongodb-org-server \ + && apt-get clean COPY --from=build /go/bin/coap-gateway /usr/local/bin/coap-gateway COPY --from=build /go/src/github.com/plgd-dev/hub/coap-gateway/config.yaml /configs/coap-gateway.yaml diff --git a/bundle/client/grpc/main.go b/bundle/client/grpc/main.go index ae9372d13..11659f814 100644 --- a/bundle/client/grpc/main.go +++ b/bundle/client/grpc/main.go @@ -63,7 +63,7 @@ func getServiceToken(authAddr string, tls *tls.Config) (string, error) { } token := body["access_token"] if token == "" { - return "", fmt.Errorf("token not found in body") + return "", errors.New("token not found in body") } return token, nil } @@ -235,7 +235,7 @@ func main() { *accesstoken = getAccessToken(*authAddr, &tlsCfg) } - conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(credentials.NewTLS(&tlsCfg))) + conn, err := grpc.NewClient(*addr, grpc.WithTransportCredentials(credentials.NewTLS(&tlsCfg))) if err != nil { log.Fatalf("Error dialing: %v", err) } diff --git a/bundle/client/ob/main.go b/bundle/client/ob/main.go index 024d91d45..9f88fdd43 100644 --- a/bundle/client/ob/main.go +++ b/bundle/client/ob/main.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/tls" + "errors" "flag" "fmt" "log" @@ -66,7 +67,7 @@ func getServiceToken(authAddr string) (string, error) { } token := body["access_token"] if token == "" { - return "", fmt.Errorf("token not found in body") + return "", errors.New("token not found in body") } return token, nil } @@ -177,7 +178,7 @@ func main() { tlsCfg := tls.Config{ InsecureSkipVerify: true, } - grpcConn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(credentials.NewTLS(&tlsCfg))) + grpcConn, err := grpc.NewClient(*addr, grpc.WithTransportCredentials(credentials.NewTLS(&tlsCfg))) if err != nil { log.Fatalf("cannot connect to grpc: %v", err) } diff --git a/certificate-authority/pb/cert.pb.go b/certificate-authority/pb/cert.pb.go index 9138cacbd..49930758d 100644 --- a/certificate-authority/pb/cert.pb.go +++ b/certificate-authority/pb/cert.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: certificate-authority/pb/cert.proto package pb diff --git a/certificate-authority/pb/service.pb.gw.go b/certificate-authority/pb/service.pb.gw.go index 53f7b133a..4c6a95371 100644 --- a/certificate-authority/pb/service.pb.gw.go +++ b/certificate-authority/pb/service.pb.gw.go @@ -35,11 +35,7 @@ func request_CertificateAuthority_SignIdentityCertificate_0(ctx context.Context, var protoReq SignCertificateRequest var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -52,11 +48,7 @@ func local_request_CertificateAuthority_SignIdentityCertificate_0(ctx context.Co var protoReq SignCertificateRequest var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -69,11 +61,7 @@ func request_CertificateAuthority_SignCertificate_0(ctx context.Context, marshal var protoReq SignCertificateRequest var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -86,11 +74,7 @@ func local_request_CertificateAuthority_SignCertificate_0(ctx context.Context, m var protoReq SignCertificateRequest var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -257,21 +241,21 @@ func RegisterCertificateAuthorityHandlerServer(ctx context.Context, mux *runtime // RegisterCertificateAuthorityHandlerFromEndpoint is same as RegisterCertificateAuthorityHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterCertificateAuthorityHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.DialContext(ctx, endpoint, opts...) + conn, err := grpc.NewClient(endpoint, opts...) if err != nil { return err } defer func() { if err != nil { if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } return } go func() { <-ctx.Done() if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } }() }() diff --git a/certificate-authority/pb/service_grpc.pb.go b/certificate-authority/pb/service_grpc.pb.go index 3cc06d62b..677e76a77 100644 --- a/certificate-authority/pb/service_grpc.pb.go +++ b/certificate-authority/pb/service_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc v5.26.1 // source: certificate-authority/pb/service.proto package pb diff --git a/certificate-authority/pb/signingRecords.go b/certificate-authority/pb/signingRecords.go index 6fa3654d2..b6eccf5cf 100644 --- a/certificate-authority/pb/signingRecords.go +++ b/certificate-authority/pb/signingRecords.go @@ -1,6 +1,7 @@ package pb import ( + "errors" "fmt" "sort" @@ -26,7 +27,7 @@ func (signingRecord *SigningRecord) Unmarshal(b []byte) error { func (signingRecord *SigningRecord) Validate() error { if signingRecord.GetId() == "" { - return fmt.Errorf("empty signing record ID") + return errors.New("empty signing record ID") } if _, err := uuid.Parse(signingRecord.GetId()); err != nil { return fmt.Errorf("invalid signing record ID(%v): %w", signingRecord.GetId(), err) @@ -37,19 +38,19 @@ func (signingRecord *SigningRecord) Validate() error { } } if signingRecord.GetCommonName() == "" { - return fmt.Errorf("empty signing record commonName") + return errors.New("empty signing record commonName") } if signingRecord.GetOwner() == "" { - return fmt.Errorf("empty signing record owner") + return errors.New("empty signing record owner") } if signingRecord.GetCredential() != nil && signingRecord.GetCredential().GetDate() == 0 { - return fmt.Errorf("empty signing credential date") + return errors.New("empty signing credential date") } if signingRecord.GetCredential() != nil && signingRecord.GetCredential().GetValidUntilDate() == 0 { - return fmt.Errorf("empty signing record credential expiration date") + return errors.New("empty signing record credential expiration date") } if signingRecord.GetCredential() != nil && signingRecord.GetCredential().GetCertificatePem() == "" { - return fmt.Errorf("empty signing record credential certificate") + return errors.New("empty signing record credential certificate") } return nil } diff --git a/certificate-authority/pb/signingRecords.pb.go b/certificate-authority/pb/signingRecords.pb.go index 1ecab2383..96739334a 100644 --- a/certificate-authority/pb/signingRecords.pb.go +++ b/certificate-authority/pb/signingRecords.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: certificate-authority/pb/signingRecords.proto package pb diff --git a/certificate-authority/service/cleanDatabase_test.go b/certificate-authority/service/cleanDatabase_test.go index 529c983cd..29ba16dbb 100644 --- a/certificate-authority/service/cleanDatabase_test.go +++ b/certificate-authority/service/cleanDatabase_test.go @@ -3,6 +3,7 @@ package service_test import ( "context" "errors" + "fmt" "io" "testing" "time" @@ -26,6 +27,7 @@ func TestCertificateAuthorityServerCleanUpSigningRecords(t *testing.T) { cfg := test.MakeConfig(t) cfg.Clients.Storage.ExtendCronParserBySeconds = true cfg.Clients.Storage.CleanUpRecords = "*/1 * * * * *" + fmt.Printf("%v\n\n", test.MakeConfig(t)) shutDown := testService.SetUpServices(context.Background(), t, testService.SetUpServicesCertificateAuthority|testService.SetUpServicesOAuth, testService.WithCAConfig(cfg)) defer shutDown() @@ -76,23 +78,25 @@ func TestCertificateAuthorityServerCleanUpSigningRecords(t *testing.T) { require.NoError(t, err) var got pb.SigningRecords for { - r, err := client.Recv() - if errors.Is(err, io.EOF) { + r, errR := client.Recv() + if errors.Is(errR, io.EOF) { break } + require.NoError(t, errR) got = append(got, r) } - require.Equal(t, 1, len(got)) + require.Len(t, got, 1) time.Sleep(4 * time.Second) client, err = grpcClient.GetSigningRecords(ctx, &pb.GetSigningRecordsRequest{}) require.NoError(t, err) got = nil for { - r, err := client.Recv() - if errors.Is(err, io.EOF) { + r, errR := client.Recv() + if errors.Is(errR, io.EOF) { break } + require.NoError(t, errR) got = append(got, r) } - require.Equal(t, 0, len(got)) + require.Empty(t, got) } diff --git a/certificate-authority/service/config.go b/certificate-authority/service/config.go index a9583fe47..7a0852e2c 100644 --- a/certificate-authority/service/config.go +++ b/certificate-authority/service/config.go @@ -5,7 +5,7 @@ import ( "net" "time" - gocron "github.com/go-co-op/gocron" + "github.com/go-co-op/gocron/v2" "github.com/google/uuid" grpcService "github.com/plgd-dev/hub/v2/certificate-authority/service/grpc" storeConfig "github.com/plgd-dev/hub/v2/certificate-authority/store/config" @@ -89,20 +89,22 @@ func (c *StorageConfig) Validate() error { if c.CleanUpRecords == "" { return nil } - s := gocron.NewScheduler(time.Local) - if c.ExtendCronParserBySeconds { - s = s.CronWithSeconds(c.CleanUpRecords) - } else { - s = s.Cron(c.CleanUpRecords) + s, err := gocron.NewScheduler(gocron.WithLocation(time.Local)) //nolint:gosmopolitan + if err != nil { + return fmt.Errorf("cannot create cron job: %w", err) } - _, err := s.Do(func() { - // do nothing - }) + defer func() { + if errS := s.Shutdown(); errS != nil { + log.Errorf("failed to shutdown cron job: %w", errS) + } + }() + _, err = s.NewJob(gocron.CronJob(c.CleanUpRecords, c.ExtendCronParserBySeconds), + gocron.NewTask(func() { + // do nothing + })) if err != nil { return fmt.Errorf("cleanUpRecords('%v') - %w", c.CleanUpRecords, err) } - s.Clear() - s.Stop() return nil } diff --git a/certificate-authority/service/config_test.go b/certificate-authority/service/config_test.go new file mode 100644 index 000000000..58427612d --- /dev/null +++ b/certificate-authority/service/config_test.go @@ -0,0 +1,203 @@ +// ************************************************************************ +// Copyright (C) 2022 plgd.dev, s.r.o. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ************************************************************************ + +package service_test + +import ( + "testing" + + "github.com/plgd-dev/hub/v2/certificate-authority/service" + "github.com/plgd-dev/hub/v2/certificate-authority/test" + "github.com/stretchr/testify/require" +) + +func TestConfigValidate(t *testing.T) { + type args struct { + cfg service.Config + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "valid", + args: args{ + cfg: func() service.Config { + c := test.MakeConfig(t) + c.Clients.Storage.ExtendCronParserBySeconds = true + c.Clients.Storage.CleanUpRecords = "*/1 * * * * *" + return c + }(), + }, + }, + { + name: "invalid log config", + args: args{ + cfg: func() service.Config { + c := test.MakeConfig(t) + c.Log.Level = 42 + return c + }(), + }, + wantErr: true, + }, + { + name: "invalid grpc api config", + args: args{ + cfg: func() service.Config { + c := test.MakeConfig(t) + c.APIs.GRPC.Addr = "invalid" + return c + }(), + }, + wantErr: true, + }, + { + name: "invalid http api config", + args: args{ + cfg: func() service.Config { + c := test.MakeConfig(t) + c.APIs.HTTP.Addr = "invalid" + return c + }(), + }, + wantErr: true, + }, + { + name: "invalid signer config", + args: args{ + cfg: func() service.Config { + c := test.MakeConfig(t) + c.Signer.CAPool = 42 + return c + }(), + }, + wantErr: true, + }, + { + name: "invalid clients storage config", + args: args{ + cfg: func() service.Config { + c := test.MakeConfig(t) + c.Clients.Storage.CleanUpRecords = "invalid" + return c + }(), + }, + wantErr: true, + }, + { + name: "invalid clients telemetry config", + args: args{ + cfg: func() service.Config { + c := test.MakeConfig(t) + c.Clients.OpenTelemetryCollector.GRPC.Enabled = true + c.Clients.OpenTelemetryCollector.GRPC.Connection.Addr = "" + return c + }(), + }, + wantErr: true, + }, + { + name: "invalid hubID", + args: args{ + cfg: func() service.Config { + c := test.MakeConfig(t) + c.HubID = "invalid" + return c + }(), + }, + wantErr: true, + }, + { + name: "invalid signer", + args: args{ + cfg: func() service.Config { + c := test.MakeConfig(t) + c.Signer.CertFile = "invalid" + return c + }(), + }, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.args.cfg.Validate() + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +} + +func TestStorageConfigValidate(t *testing.T) { + type args struct { + cfg service.StorageConfig + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "valid - disabled", + args: args{ + cfg: func() service.StorageConfig { + c := test.MakeStorageConfig() + c.CleanUpRecords = "" + return c + }(), + }, + }, + { + name: "invalid", + args: args{ + cfg: func() service.StorageConfig { + c := test.MakeStorageConfig() + c.CleanUpRecords = "invalid" + return c + }(), + }, + wantErr: true, + }, + { + name: "invalid db", + args: args{ + cfg: func() service.StorageConfig { + c := test.MakeStorageConfig() + c.Embedded.Use = "invalid" + return c + }(), + }, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.args.cfg.Validate() + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +} diff --git a/certificate-authority/service/grpc/deleteSigningRecords_test.go b/certificate-authority/service/grpc/deleteSigningRecords_test.go index e1a6e9c88..573fdff84 100644 --- a/certificate-authority/service/grpc/deleteSigningRecords_test.go +++ b/certificate-authority/service/grpc/deleteSigningRecords_test.go @@ -55,7 +55,7 @@ func TestCertificateAuthorityServerDeleteSigningRecords(t *testing.T) { name: "valid", args: args{ req: &pb.DeleteSigningRecordsRequest{ - IdFilter: []string{r.Id}, + IdFilter: []string{r.GetId()}, }, }, want: 1, diff --git a/certificate-authority/service/grpc/getSigningRecords_test.go b/certificate-authority/service/grpc/getSigningRecords_test.go index 21a744c10..c7f1d859a 100644 --- a/certificate-authority/service/grpc/getSigningRecords_test.go +++ b/certificate-authority/service/grpc/getSigningRecords_test.go @@ -63,7 +63,7 @@ func TestCertificateAuthorityServerGetSigningRecords(t *testing.T) { name: "valid", args: args{ req: &pb.GetSigningRecordsRequest{ - IdFilter: []string{r.Id}, + IdFilter: []string{r.GetId()}, }, }, want: []*pb.SigningRecord{r}, diff --git a/certificate-authority/service/grpc/infoData.go b/certificate-authority/service/grpc/infoData.go index e3cd974d0..b8dc2b5d2 100644 --- a/certificate-authority/service/grpc/infoData.go +++ b/certificate-authority/service/grpc/infoData.go @@ -3,6 +3,7 @@ package grpc import ( "crypto/x509" "encoding/pem" + "errors" "fmt" "regexp" ) @@ -25,7 +26,7 @@ func (d infoData) String() string { func getInfoData(csr []byte) (infoData, error) { csrBlock, _ := pem.Decode(csr) if csrBlock == nil { - return infoData{}, fmt.Errorf("pem not found") + return infoData{}, errors.New("pem not found") } certificateRequest, err := x509.ParseCertificateRequest(csrBlock.Bytes) diff --git a/certificate-authority/service/grpc/signCertificate.go b/certificate-authority/service/grpc/signCertificate.go index 350187284..45252f07c 100644 --- a/certificate-authority/service/grpc/signCertificate.go +++ b/certificate-authority/service/grpc/signCertificate.go @@ -3,6 +3,7 @@ package grpc import ( "context" "crypto/x509" + "errors" "fmt" "regexp" "time" @@ -104,7 +105,7 @@ func (s *CertificateAuthorityServer) SignCertificate(ctx context.Context, req *p } signer := s.GetSigner() if signer == nil { - return nil, logger.LogAndReturnError(status.Errorf(codes.InvalidArgument, fmtError, fmt.Errorf("signer is empty"))) + return nil, logger.LogAndReturnError(status.Errorf(codes.InvalidArgument, fmtError, errors.New("signer is empty"))) } cert, signingRecord, err := signer.Sign(ctx, req.GetCertificateSigningRequest()) if err != nil { diff --git a/certificate-authority/service/grpc/signCertificate_test.go b/certificate-authority/service/grpc/signCertificate_test.go index 0f0d2a05a..38189e797 100644 --- a/certificate-authority/service/grpc/signCertificate_test.go +++ b/certificate-authority/service/grpc/signCertificate_test.go @@ -66,7 +66,7 @@ func testSigningByFunction(t *testing.T, signFn ClientSignFunc, csr ...[]byte) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.CERTIFICATE_AUTHORITY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.CERTIFICATE_AUTHORITY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -113,7 +113,7 @@ func TestCertificateAuthorityServerSignCSRWithDifferentPublicKeys(t *testing.T) defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.CERTIFICATE_AUTHORITY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.CERTIFICATE_AUTHORITY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/certificate-authority/service/grpc/signIdentityCertificate.go b/certificate-authority/service/grpc/signIdentityCertificate.go index ccde56cd8..be765018d 100644 --- a/certificate-authority/service/grpc/signIdentityCertificate.go +++ b/certificate-authority/service/grpc/signIdentityCertificate.go @@ -3,6 +3,7 @@ package grpc import ( "context" "crypto/x509/pkix" + "errors" "fmt" "github.com/plgd-dev/hub/v2/certificate-authority/pb" @@ -45,7 +46,7 @@ func (s *CertificateAuthorityServer) SignIdentityCertificate(ctx context.Context } signer := s.GetSigner() if signer == nil { - return nil, logger.LogAndReturnError(status.Errorf(codes.InvalidArgument, fmtError, fmt.Errorf("signer is empty"))) + return nil, logger.LogAndReturnError(status.Errorf(codes.InvalidArgument, fmtError, errors.New("signer is empty"))) } cert, signingRecord, err := signer.SignIdentityCSR(ctx, req.GetCertificateSigningRequest()) if err != nil { diff --git a/certificate-authority/service/grpc/signIdentityCertificate_test.go b/certificate-authority/service/grpc/signIdentityCertificate_test.go index 9c81133f8..a4a1b4260 100644 --- a/certificate-authority/service/grpc/signIdentityCertificate_test.go +++ b/certificate-authority/service/grpc/signIdentityCertificate_test.go @@ -51,7 +51,7 @@ func TestCertificateAuthorityServerSignDeviceIdentityCSRWithDifferentPublicKeys( defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.CERTIFICATE_AUTHORITY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.CERTIFICATE_AUTHORITY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -79,7 +79,7 @@ func TestCertificateAuthorityServerSignOwnerIdentityCSRWithDifferentPublicKeys(t defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.CERTIFICATE_AUTHORITY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.CERTIFICATE_AUTHORITY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/certificate-authority/service/grpc/signer.go b/certificate-authority/service/grpc/signer.go index d4f014afc..0b4866e0a 100644 --- a/certificate-authority/service/grpc/signer.go +++ b/certificate-authority/service/grpc/signer.go @@ -6,7 +6,6 @@ import ( "crypto/ecdsa" "crypto/x509" "errors" - "fmt" "time" "github.com/karrick/tparse/v2" @@ -26,7 +25,7 @@ type Signer struct { func checkCertificatePrivateKey(cert []*x509.Certificate, priv *ecdsa.PrivateKey) error { if len(cert) == 0 { - return fmt.Errorf("at least one certificate need to be set") + return errors.New("at least one certificate need to be set") } x509Cert := cert[0] switch pub := x509Cert.PublicKey.(type) { @@ -57,7 +56,7 @@ func NewSigner(ownerClaim string, hubID string, signerConfig SignerConfig) (*Sig if err != nil { return nil, err } - if err := checkCertificatePrivateKey(certificate, privateKey); err != nil { + if err = checkCertificatePrivateKey(certificate, privateKey); err != nil { return nil, err } if len(certificate) == 1 && pkgX509.IsRootCA(certificate[0]) { @@ -76,13 +75,13 @@ func NewSigner(ownerClaim string, hubID string, signerConfig SignerConfig) (*Sig certificateAuthorities := make([]*x509.Certificate, 0, len(signerConfig.caPoolArray)*4) for _, caFile := range signerConfig.caPoolArray { - data, err := caFile.Read() - if err != nil { - return nil, err + data, errR := caFile.Read() + if errR != nil { + return nil, errR } - certs, err := pkgX509.ParseX509(data) - if err != nil { - return nil, err + certs, errR := pkgX509.ParseX509(data) + if errR != nil { + return nil, errR } certificateAuthorities = append(certificateAuthorities, certs...) } @@ -108,21 +107,26 @@ func NewSigner(ownerClaim string, hubID string, signerConfig SignerConfig) (*Sig }, nil } +func (s *Signer) prepareSigningRecord(ctx context.Context, template *x509.Certificate) (*pb.SigningRecord, error) { + subject, err := overrideSubject(ctx, template.Subject, s.ownerClaim, s.hubID, "") + if err != nil { + return nil, err + } + template.Subject = subject + owner, err := ownerToUUID(ctx, s.ownerClaim) + if err != nil { + return nil, err + } + return toSigningRecord(owner, template) +} + func (s *Signer) Sign(ctx context.Context, csr []byte) ([]byte, *pb.SigningRecord, error) { notBefore := s.validFrom() notAfter := notBefore.Add(s.validFor) var signingRecord *pb.SigningRecord signer := certificateSigner.New(s.certificate, s.privateKey, certificateSigner.WithNotBefore(notBefore), certificateSigner.WithNotAfter(notAfter), certificateSigner.WithOverrideCertTemplate(func(template *x509.Certificate) error { - subject, err := overrideSubject(ctx, template.Subject, s.ownerClaim, s.hubID, "") - if err != nil { - return err - } - template.Subject = subject - owner, err := ownerToUUID(ctx, s.ownerClaim) - if err != nil { - return err - } - signingRecord, err = toSigningRecord(owner, template) + var err error + signingRecord, err = s.prepareSigningRecord(ctx, template) return err })) crt, err := signer.Sign(ctx, csr) @@ -134,16 +138,8 @@ func (s *Signer) SignIdentityCSR(ctx context.Context, csr []byte) ([]byte, *pb.S notAfter := notBefore.Add(s.validFor) var signingRecord *pb.SigningRecord signer := certificateSigner.NewIdentityCertificateSigner(s.certificate, s.privateKey, certificateSigner.WithNotBefore(notBefore), certificateSigner.WithNotAfter(notAfter), certificateSigner.WithOverrideCertTemplate(func(template *x509.Certificate) error { - subject, err := overrideSubject(ctx, template.Subject, s.ownerClaim, s.hubID, "uuid:") - if err != nil { - return err - } - template.Subject = subject - owner, err := ownerToUUID(ctx, s.ownerClaim) - if err != nil { - return err - } - signingRecord, err = toSigningRecord(owner, template) + var err error + signingRecord, err = s.prepareSigningRecord(ctx, template) return err })) cert, err := signer.Sign(ctx, csr) diff --git a/certificate-authority/service/service.go b/certificate-authority/service/service.go index 5312aa732..c4c240c5c 100644 --- a/certificate-authority/service/service.go +++ b/certificate-authority/service/service.go @@ -6,7 +6,7 @@ import ( "fmt" "time" - gocron "github.com/go-co-op/gocron" + "github.com/go-co-op/gocron/v2" grpcService "github.com/plgd-dev/hub/v2/certificate-authority/service/grpc" httpService "github.com/plgd-dev/hub/v2/certificate-authority/service/http" "github.com/plgd-dev/hub/v2/certificate-authority/store" @@ -52,33 +52,35 @@ func newStore(ctx context.Context, config StorageConfig, fileWatcher *fsnotify.W return nil, nil, err } fl.AddFunc(func() { - if err := db.Close(ctx); err != nil { - log.Errorf("failed to close mongodb store: %w", err) + if errC := db.Close(ctx); errC != nil { + log.Errorf("failed to close mongodb store: %w", errC) } }) if config.CleanUpRecords == "" { return db, fl.ToFunction(), nil } - s := gocron.NewScheduler(time.Local) - if config.ExtendCronParserBySeconds { - s = s.CronWithSeconds(config.CleanUpRecords) - } else { - s = s.Cron(config.CleanUpRecords) + s, err := gocron.NewScheduler(gocron.WithLocation(time.Local)) //nolint:gosmopolitan + if err != nil { + fl.Execute() + return nil, nil, fmt.Errorf("cannot create cron job: %w", err) } - _, err = s.Do(func() { + + _, err = s.NewJob(gocron.CronJob(config.CleanUpRecords, config.ExtendCronParserBySeconds), gocron.NewTask(func() { _, errDel := db.DeleteNonDeviceExpiredRecords(ctx, time.Now()) if errDel != nil && !errors.Is(errDel, store.ErrNotSupported) { log.Errorf("failed to delete expired signing records: %w", errDel) } - }) + })) if err != nil { fl.Execute() return nil, nil, fmt.Errorf("cannot create cron job: %w", err) } - fl.AddFunc(s.Clear) - fl.AddFunc(s.Stop) - s.StartAsync() - + fl.AddFunc(func() { + if errS := s.Shutdown(); errS != nil { + log.Errorf("failed to shutdown cron job: %w", errS) + } + }) + s.Start() return db, fl.ToFunction(), nil } diff --git a/certificate-authority/service/service_test.go b/certificate-authority/service/service_test.go deleted file mode 100644 index 47f7b6d81..000000000 --- a/certificate-authority/service/service_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// ************************************************************************ -// Copyright (C) 2022 plgd.dev, s.r.o. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ************************************************************************ - -package service_test - -import ( - "context" - "fmt" - "testing" - - "github.com/plgd-dev/hub/v2/certificate-authority/test" - testService "github.com/plgd-dev/hub/v2/test/service" - "github.com/stretchr/testify/require" -) - -func TestServiceServe(t *testing.T) { - fmt.Printf("%v\n\n", test.MakeConfig(t)) - - shutDown := testService.SetUpServices(context.Background(), t, testService.SetUpServicesCertificateAuthority|testService.SetUpServicesOAuth) - defer shutDown() - - cfg := test.MakeConfig(t) - cfg.Clients.Storage.CleanUpRecords = "/2 * * * *" - require.Error(t, cfg.Validate()) -} diff --git a/certificate-authority/store/cqldb/signingRecords.go b/certificate-authority/store/cqldb/signingRecords.go index 5ae8e3629..73924579c 100644 --- a/certificate-authority/store/cqldb/signingRecords.go +++ b/certificate-authority/store/cqldb/signingRecords.go @@ -81,7 +81,7 @@ func (s *Store) CreateSigningRecord(ctx context.Context, signingRecord *store.Si return err } if !applied { - return fmt.Errorf("cannot insert signing record: already exists") + return errors.New("cannot insert signing record: already exists") } return nil } @@ -251,7 +251,7 @@ func (s *Store) deviceIDFilterToPrimaryKeys(ctx context.Context, owner string, d func (s *Store) ownerFilterToPrimaryKeys(ctx context.Context, owner string) (primaryKeysValues, error) { if owner == "" { - return nil, fmt.Errorf("invalid owner") + return nil, errors.New("invalid owner") } var b strings.Builder @@ -393,7 +393,7 @@ func (i *SigningRecordsIterator) close() error { func (i *SigningRecordsIterator) Next(_ context.Context, s *store.SigningRecord) bool { for i.next(s) { - if _, ok := i.provided[s.Id]; !ok { + if _, ok := i.provided[s.GetId()]; !ok { // filter duplicated records i.provided[s.GetId()] = struct{}{} return true diff --git a/certificate-authority/store/cqldb/signingRecords_test.go b/certificate-authority/store/cqldb/signingRecords_test.go index 918252230..f2421c41d 100644 --- a/certificate-authority/store/cqldb/signingRecords_test.go +++ b/certificate-authority/store/cqldb/signingRecords_test.go @@ -175,8 +175,8 @@ func TestStoreUpdateSigningRecord(t *testing.T) { } require.NoError(t, err) var h testSigningRecordHandler - err = s.LoadSigningRecords(ctx, tt.args.sub.Owner, &pb.GetSigningRecordsRequest{ - IdFilter: []string{tt.args.sub.Id}, + err = s.LoadSigningRecords(ctx, tt.args.sub.GetOwner(), &pb.GetSigningRecordsRequest{ + IdFilter: []string{tt.args.sub.GetId()}, }, h.Handle) require.NoError(t, err) require.Len(t, h.lcs, 1) @@ -355,7 +355,7 @@ func TestStoreDeleteExpiredRecords(t *testing.T) { var h1 testSigningRecordHandler err = s.LoadSigningRecords(ctx, "owner", nil, h1.Handle) require.NoError(t, err) - require.Len(t, h1.lcs, 0) + require.Empty(t, h1.lcs) } type testSigningRecordHandler struct { @@ -467,7 +467,7 @@ func TestStoreLoadSigningRecords(t *testing.T) { name: "id - another owner", args: args{ owner: "another owner", - query: &store.SigningRecordsQuery{IdFilter: []string{lcs[1].Id}}, + query: &store.SigningRecordsQuery{IdFilter: []string{lcs[1].GetId()}}, }, want: []*store.SigningRecord{lcs[1]}, }, @@ -475,7 +475,7 @@ func TestStoreLoadSigningRecords(t *testing.T) { name: "multiple queries", args: args{ owner: "owner", - query: &store.SigningRecordsQuery{IdFilter: []string{lcs[0].Id, lcs[2].Id}}, + query: &store.SigningRecordsQuery{IdFilter: []string{lcs[0].GetId(), lcs[2].GetId()}}, }, want: []*store.SigningRecord{lcs[0], lcs[2]}, }, @@ -498,7 +498,7 @@ func TestStoreLoadSigningRecords(t *testing.T) { args: args{ owner: "owner", query: &store.SigningRecordsQuery{ - IdFilter: []string{lcs[0].Id, lcs[2].Id}, + IdFilter: []string{lcs[0].GetId(), lcs[2].GetId()}, DeviceIdFilter: []string{lcs[0].GetDeviceId()}, }, }, @@ -520,10 +520,10 @@ func TestStoreLoadSigningRecords(t *testing.T) { var h testSigningRecordHandler err := s.LoadSigningRecords(ctx, "owner", tt.args.query, h.Handle) if tt.wantErr { - assert.Error(t, err) + require.Error(t, err) return } - assert.NoError(t, err) + require.NoError(t, err) require.Len(t, h.lcs, len(tt.want)) h.lcs.Sort() tt.want.Sort() @@ -570,7 +570,7 @@ func BenchmarkSigningRecords(b *testing.B) { go func(l *pb.SigningRecord) { defer wg.Done() err := s.UpdateSigningRecord(ctx, l) - require.NoError(b, err) + assert.NoError(b, err) }(l) } wg.Wait() diff --git a/certificate-authority/store/mongodb/signingRecords.go b/certificate-authority/store/mongodb/signingRecords.go index 124339e91..1217f9ca7 100644 --- a/certificate-authority/store/mongodb/signingRecords.go +++ b/certificate-authority/store/mongodb/signingRecords.go @@ -79,7 +79,12 @@ func toSigningRecordsQueryFilter(owner string, queries *store.SigningRecordsQuer } switch len(or) { case 0: - return bson.D{} + if owner == "" { + return bson.D{} + } + return bson.D{ + {Key: store.OwnerKey, Value: owner}, + } case 1: return or[0] } @@ -91,7 +96,7 @@ func (s *Store) DeleteSigningRecords(ctx context.Context, owner string, query *s IdFilter: query.GetIdFilter(), DeviceIdFilter: query.GetDeviceIdFilter(), } - res, err := s.Collection(signingRecordsCol).DeleteOne(ctx, toSigningRecordsQueryFilter(owner, &q)) + res, err := s.Collection(signingRecordsCol).DeleteMany(ctx, toSigningRecordsQueryFilter(owner, &q)) if err != nil { return -1, multierror.Append(ErrCannotRemoveSigningRecord, err) } diff --git a/certificate-authority/store/mongodb/signingRecords_test.go b/certificate-authority/store/mongodb/signingRecords_test.go index ff8e81549..312f1a29b 100644 --- a/certificate-authority/store/mongodb/signingRecords_test.go +++ b/certificate-authority/store/mongodb/signingRecords_test.go @@ -93,9 +93,9 @@ func TestStoreUpdateSigningRecord(t *testing.T) { t.Run(tt.name, func(t *testing.T) { err := s.UpdateSigningRecord(ctx, tt.args.sub) if tt.wantErr { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) + require.NoError(t, err) } err = s.FlushBulkWriter() require.NoError(t, err) @@ -103,11 +103,28 @@ func TestStoreUpdateSigningRecord(t *testing.T) { } } -func TestStoreDeleteSigningRecord(t *testing.T) { - const id1 = "9d017fad-2961-4fcc-94a9-1e1291a88ffc" - deviceID1 := hubTest.GenerateDeviceIDbyIdx(1) - const id2 = "9d017fad-2961-4fcc-94a9-1e1291a88ffd" - deviceID2 := hubTest.GenerateDeviceIDbyIdx(2) +func TestStoreDeleteSigningRecords(t *testing.T) { + records := []struct { + id string + deviceID string + }{ + { + id: "9d017fad-2961-4fcc-94a9-1e1291a88ffc", + deviceID: hubTest.GenerateDeviceIDbyIdx(1), + }, + { + id: "9d017fad-2961-4fcc-94a9-1e1291a88ffd", + deviceID: hubTest.GenerateDeviceIDbyIdx(2), + }, + { + id: "9d017fad-2961-4fcc-94a9-1e1291a88ffe", + deviceID: hubTest.GenerateDeviceIDbyIdx(3), + }, + { + id: "9d017fad-2961-4fcc-94a9-1e1291a88fff", + deviceID: hubTest.GenerateDeviceIDbyIdx(4), + }, + } const owner = "owner" type args struct { owner string @@ -134,7 +151,7 @@ func TestStoreDeleteSigningRecord(t *testing.T) { args: args{ owner: "owner1", query: &store.DeleteSigningRecordsQuery{ - IdFilter: []string{id1}, + IdFilter: []string{records[0].id}, }, }, want: 0, @@ -144,7 +161,7 @@ func TestStoreDeleteSigningRecord(t *testing.T) { args: args{ owner: owner, query: &store.DeleteSigningRecordsQuery{ - DeviceIdFilter: []string{deviceID1}, + DeviceIdFilter: []string{records[0].deviceID}, }, }, want: 1, @@ -154,11 +171,21 @@ func TestStoreDeleteSigningRecord(t *testing.T) { args: args{ owner: owner, query: &store.DeleteSigningRecordsQuery{ - IdFilter: []string{id2}, + IdFilter: []string{records[1].id}, }, }, want: 1, }, + { + name: "multiple ids", + args: args{ + owner: owner, + query: &store.DeleteSigningRecordsQuery{ + IdFilter: []string{records[2].id, records[3].id}, + }, + }, + want: 2, + }, { name: "valid - empty", args: args{ @@ -173,43 +200,31 @@ func TestStoreDeleteSigningRecord(t *testing.T) { defer cleanUpStore() ctx := context.Background() - err := s.CreateSigningRecord(ctx, &store.SigningRecord{ - Id: id1, - Owner: owner, - CommonName: "commonName", - PublicKey: "publicKey", - DeviceId: deviceID1, - CreationDate: constDate().UnixNano(), - Credential: &pb.CredentialStatus{ - CertificatePem: "certificate", - Date: constDate().UnixNano(), - ValidUntilDate: constDate().UnixNano(), - }, - }) - require.NoError(t, err) - err = s.CreateSigningRecord(ctx, &store.SigningRecord{ - Id: id2, - Owner: owner, - CommonName: "commonName", - PublicKey: "publicKey", - DeviceId: deviceID2, - CreationDate: constDate().UnixNano(), - Credential: &pb.CredentialStatus{ - CertificatePem: "certificate", - Date: constDate().UnixNano(), - ValidUntilDate: constDate().UnixNano(), - }, - }) - require.NoError(t, err) + for _, r := range records { + err := s.CreateSigningRecord(ctx, &store.SigningRecord{ + Id: r.id, + Owner: owner, + CommonName: "commonName", + PublicKey: "publicKey", + DeviceId: r.deviceID, + CreationDate: constDate().UnixNano(), + Credential: &pb.CredentialStatus{ + CertificatePem: "certificate", + Date: constDate().UnixNano(), + ValidUntilDate: constDate().UnixNano(), + }, + }) + require.NoError(t, err) + } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { n, err := s.DeleteSigningRecords(ctx, tt.args.owner, tt.args.query) if tt.wantErr { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) - assert.Equal(t, tt.want, n) + require.NoError(t, err) + require.Equal(t, tt.want, n) } }) } @@ -268,8 +283,8 @@ func TestStoreDeleteExpiredRecords(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := s.DeleteNonDeviceExpiredRecords(ctx, tt.args.now) - assert.NoError(t, err) - assert.Equal(t, tt.want, got) + require.NoError(t, err) + require.Equal(t, tt.want, got) }) } } @@ -293,10 +308,13 @@ func TestStoreLoadSigningRecords(t *testing.T) { const id = "9d017fad-2961-4fcc-94a9-1e1291a88ffc" const id1 = "9d017fad-2961-4fcc-94a9-1e1291a88ffd" const id2 = "9d017fad-2961-4fcc-94a9-1e1291a88ffe" + const owner = "owner" + const differentOwner = "owner2" + const differentOwnerRecordId = "9d017fad-2961-4fcc-94a9-1e1291a88fff" upds := pb.SigningRecords{ { Id: id, - Owner: "owner", + Owner: owner, CommonName: "commonName", PublicKey: "publicKey", DeviceId: hubTest.GenerateDeviceIDbyIdx(0), @@ -309,7 +327,7 @@ func TestStoreLoadSigningRecords(t *testing.T) { }, { Id: id1, - Owner: "owner", + Owner: owner, CommonName: "commonName1", CreationDate: constDate().UnixNano(), PublicKey: "publicKey", @@ -322,7 +340,7 @@ func TestStoreLoadSigningRecords(t *testing.T) { }, { Id: id2, - Owner: "owner", + Owner: owner, CommonName: "commonName2", CreationDate: constDate().UnixNano(), PublicKey: "publicKey", @@ -333,6 +351,19 @@ func TestStoreLoadSigningRecords(t *testing.T) { ValidUntilDate: constDate().UnixNano(), }, }, + { + Id: differentOwnerRecordId, + Owner: differentOwner, + CommonName: "commonName2", + CreationDate: constDate().UnixNano(), + PublicKey: "publicKey", + DeviceId: hubTest.GenerateDeviceIDbyIdx(3), + Credential: &pb.CredentialStatus{ + CertificatePem: "certificate", + Date: constDate().UnixNano(), + ValidUntilDate: constDate().UnixNano(), + }, + }, } lcs := upds @@ -356,7 +387,7 @@ func TestStoreLoadSigningRecords(t *testing.T) { { name: "id", args: args{ - owner: "owner", + owner: owner, query: &store.SigningRecordsQuery{IdFilter: []string{lcs[1].GetId()}}, }, want: []*store.SigningRecord{lcs[1]}, @@ -364,7 +395,7 @@ func TestStoreLoadSigningRecords(t *testing.T) { { name: "commonName", args: args{ - owner: "owner", + owner: owner, query: &store.SigningRecordsQuery{CommonNameFilter: []string{lcs[1].GetCommonName()}}, }, want: []*store.SigningRecord{lcs[1]}, @@ -372,26 +403,40 @@ func TestStoreLoadSigningRecords(t *testing.T) { { name: "DeviceID", args: args{ - owner: "owner", + owner: owner, query: &store.SigningRecordsQuery{DeviceIdFilter: []string{lcs[1].GetDeviceId()}}, }, want: []*store.SigningRecord{lcs[1]}, }, { - name: "id - another owner", + name: "multiple queries", args: args{ - owner: "another owner", - query: &store.SigningRecordsQuery{IdFilter: []string{lcs[1].Id}}, + owner: owner, + query: &store.SigningRecordsQuery{IdFilter: []string{lcs[0].GetId(), lcs[2].GetId()}}, }, - want: []*store.SigningRecord{lcs[1]}, + want: []*store.SigningRecord{lcs[0], lcs[2]}, }, { - name: "multiple queries", + name: "different owner", args: args{ - owner: "owner", - query: &store.SigningRecordsQuery{IdFilter: []string{lcs[0].Id, lcs[2].Id}}, + owner: differentOwner, + }, + want: []*store.SigningRecord{lcs[3]}, + }, + { + name: "different owner - id", + args: args{ + owner: differentOwner, + query: &store.SigningRecordsQuery{IdFilter: []string{differentOwnerRecordId}}, + }, + want: []*store.SigningRecord{lcs[3]}, + }, + { + name: "different owner but id belongs to owner", + args: args{ + owner: differentOwner, + query: &store.SigningRecordsQuery{IdFilter: []string{lcs[1].GetId()}}, }, - want: []*store.SigningRecord{lcs[0], lcs[2]}, }, { name: "all records", @@ -403,7 +448,7 @@ func TestStoreLoadSigningRecords(t *testing.T) { { name: "not found", args: args{ - owner: "owner", + owner: owner, query: &store.SigningRecordsQuery{IdFilter: []string{"not found"}}, }, }, @@ -421,7 +466,7 @@ func TestStoreLoadSigningRecords(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var h testSigningRecordHandler - err := s.LoadSigningRecords(ctx, "owner", tt.args.query, h.Handle) + err := s.LoadSigningRecords(ctx, tt.args.owner, tt.args.query, h.Handle) require.NoError(t, err) require.Len(t, h.lcs, len(tt.want)) h.lcs.Sort() @@ -468,12 +513,12 @@ func BenchmarkSigningRecords(b *testing.B) { go func(l *pb.SigningRecord) { defer wg.Done() err := s.UpdateSigningRecord(ctx, l) - require.NoError(b, err) + assert.NoError(b, err) }(l) } wg.Wait() err := s.FlushBulkWriter() - require.NoError(b, err) + assert.NoError(b, err) }() } } diff --git a/certificate-authority/store/mongodb/store.go b/certificate-authority/store/mongodb/store.go index f1c1bb5b5..90b0115cf 100644 --- a/certificate-authority/store/mongodb/store.go +++ b/certificate-authority/store/mongodb/store.go @@ -49,9 +49,7 @@ func New(ctx context.Context, cfg *Config, fileWatcher *fsnotify.Watcher, logger certManager.Close() return nil, err } - s.SetOnClear(func(c context.Context) error { - return s.clearDatabases(ctx) - }) + s.SetOnClear(s.clearDatabases) s.AddCloseFunc(certManager.Close) return &s, nil } diff --git a/charts/plgd-hub/Chart.lock b/charts/plgd-hub/Chart.lock index 63f6c64c9..aac7c15ab 100644 --- a/charts/plgd-hub/Chart.lock +++ b/charts/plgd-hub/Chart.lock @@ -1,12 +1,12 @@ dependencies: - name: nats repository: https://nats-io.github.io/k8s/helm/charts/ - version: 0.19.14 + version: 1.1.9 - name: mongodb repository: https://charts.bitnami.com/bitnami - version: 13.4.3 + version: 13.18.3 - name: scylla repository: https://scylla-operator-charts.storage.googleapis.com/stable version: v1.10.0 -digest: sha256:19d6a1d0ed96e796922eeeb3d1e4920f1aea3774af332a5f8704b190a5e428fe -generated: "2023-11-03T15:24:42.261277287Z" +digest: sha256:3ed14035e169597cbd91e8521414c8bbae13879d27bda6726ce45b1e74572050 +generated: "2024-03-05T10:43:45.524423289Z" diff --git a/charts/plgd-hub/Chart.yaml b/charts/plgd-hub/Chart.yaml index 9dab65931..91c970029 100644 --- a/charts/plgd-hub/Chart.yaml +++ b/charts/plgd-hub/Chart.yaml @@ -11,11 +11,11 @@ appVersion: vnext dependencies: - name: "nats" - version: "0.19.14" + version: "1.1.9" repository: "https://nats-io.github.io/k8s/helm/charts/" condition: nats.enabled - name: "mongodb" - version: "13.4.3" + version: "13.18.3" repository: "https://charts.bitnami.com/bitnami" condition: mongodb.enabled - name: "scylla" diff --git a/charts/plgd-hub/README.md b/charts/plgd-hub/README.md index 9f2c56415..6ffe125fd 100644 --- a/charts/plgd-hub/README.md +++ b/charts/plgd-hub/README.md @@ -45,8 +45,8 @@ global: | Repository | Name | Version | |------------|------|---------| -| https://charts.bitnami.com/bitnami | mongodb | 13.4.3 | -| https://nats-io.github.io/k8s/helm/charts/ | nats | 0.19.14 | +| https://charts.bitnami.com/bitnami | mongodb | 13.18.3 | +| https://nats-io.github.io/k8s/helm/charts/ | nats | 1.1.8 | | https://scylla-operator-charts.storage.googleapis.com/stable | scylla | 1.10.0 | ## Values @@ -70,11 +70,15 @@ global: | certificateauthority.clients.storage.cqlDB.keyspace.replication.class | string | `"SimpleStrategy"` | | | certificateauthority.clients.storage.cqlDB.keyspace.replication.replication_factor | int | `1` | | | certificateauthority.clients.storage.cqlDB.numConnections | int | `16` | | +| certificateauthority.clients.storage.cqlDB.port | int | `9142` | | +| certificateauthority.clients.storage.cqlDB.reconnectionPolicy.constant.interval | string | `"3s"` | | +| certificateauthority.clients.storage.cqlDB.reconnectionPolicy.constant.maxRetries | int | `3` | | | certificateauthority.clients.storage.cqlDB.table | string | `"signedCertificateRecords"` | | | certificateauthority.clients.storage.cqlDB.tls.caPool | string | `nil` | | | certificateauthority.clients.storage.cqlDB.tls.certFile | string | `nil` | | | certificateauthority.clients.storage.cqlDB.tls.keyFile | string | `nil` | | | certificateauthority.clients.storage.cqlDB.tls.useSystemCAPool | bool | `false` | | +| certificateauthority.clients.storage.cqlDB.useHostnameResolution | bool | `true` | Resolve IP address to hostname before validate certificate. If false, the TLS validator will use ip/hostname advertised by the Cassandra node. | | certificateauthority.clients.storage.mongoDB.bulkWrite.documentLimit | int | `1000` | The maximum number of documents to cache before an immediate write. | | certificateauthority.clients.storage.mongoDB.bulkWrite.throttleTime | string | `"500ms"` | The amount of time to wait until a record is written to mongodb. Any records collected during the throttle time will also be written. A throttle time of zero writes immediately. If recordLimit is reached, all records are written immediately | | certificateauthority.clients.storage.mongoDB.bulkWrite.timeout | string | `"1m0s"` | A time limit for write bulk to mongodb. A Timeout of zero means no timeout. | @@ -295,7 +299,7 @@ global: | extraAuthorizationCAPool.mountPath | string | `"/certs/extra"` | Mount path for custom auth ca pool | | extraAuthorizationCAPool.name | string | `"authorization-ca-pool"` | Name of secret for storing custom auth ca pool | | extraDeploy | string | `nil` | Extra deploy. Resolved as template | -| global | object | `{"audience":"","authority":null,"authorizationCAPool":null,"defaultCommandTimeToLive":"10s","deviceIdClaim":null,"domain":null,"enableWildCartCert":true,"hubId":null,"oauth":{"device":[],"web":{"clientID":null,"scopes":["openid"]}},"openTelemetryExporter":{"address":null,"enabled":false,"keepAlive":{"permitWithoutStream":true,"time":"10s","timeout":"20s"},"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}},"ownerClaim":"sub"}` | Global config variables | +| global | object | `{"audience":"","authority":null,"authorizationCAPool":null,"defaultCommandTimeToLive":"10s","deviceIdClaim":null,"domain":null,"enableWildCartCert":true,"hubId":null,"oauth":{"device":[],"web":{"clientID":null,"scopes":["openid"]}},"openTelemetryExporter":{"address":null,"enabled":false,"keepAlive":{"permitWithoutStream":true,"time":"10s","timeout":"20s"},"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}},"ownerClaim":"sub","useDatabase":"mongoDB"}` | Global config variables | | global.audience | string | `""` | OAuth audience | | global.authority | string | `nil` | OAuth authority | | global.authorizationCAPool | string | `nil` | Custom CA certificate for authorization endpoint in PEM format | @@ -311,6 +315,7 @@ global: | global.openTelemetryExporter.keepAlive | object | `{"permitWithoutStream":true,"time":"10s","timeout":"20s"}` | Expoter keep alive configuration | | global.openTelemetryExporter.tls | object | `{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}` | Expoter TLS configuration | | global.ownerClaim | string | `"sub"` | OAuth owner Claim | +| global.useDatabase | string | `"mongoDB"` | Use database. Supported values: "mongoDB", "cqlDB" | | grpcgateway.affinity | object | `{}` | Affinity definition | | grpcgateway.apis | object | `{"grpc":{"address":null,"authorization":{"audience":"","authority":"","http":{"idleConnTimeout":"30s","maxConnsPerHost":32,"maxIdleConns":16,"maxIdleConnsPerHost":16,"timeout":"10s","tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":true}}},"enforcementPolicy":{"minTime":"5s","permitWithoutStream":true},"keepAlive":{"maxConnectionAge":"0s","maxConnectionAgeGrace":"0s","maxConnectionIdle":"0s","time":"2h","timeout":"20s"},"ownerCacheExpiration":"1m","recvMsgSize":4194304,"sendMsgSize":4194304,"subscriptionBufferSize":1000,"tls":{"caPool":null,"certFile":null,"clientCertificateRequired":false,"keyFile":null}}}` | For complete grpc-gateway service configuration see [plgd/grpc-gateway](https://github.com/plgd-dev/hub/tree/main/grpc-gateway) | | grpcgateway.clients | object | `{"certificateAuthority":{"grpc":{"address":"","keepAlive":{"permitWithoutStream":true,"time":"10s","timeout":"20s"},"recvMsgSize":4194304,"sendMsgSize":4194304,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}}},"eventBus":{"goPoolSize":16,"nats":{"pendingLimits":{"bytesLimit":"67108864","msgLimit":524288},"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"url":null}},"identityStore":{"grpc":{"address":"","keepAlive":{"permitWithoutStream":true,"time":"10s","timeout":"20s"},"recvMsgSize":4194304,"sendMsgSize":4194304,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}}},"resourceAggregate":{"grpc":{"address":"","keepAlive":{"permitWithoutStream":true,"time":"10s","timeout":"20s"},"recvMsgSize":4194304,"sendMsgSize":4194304,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}}},"resourceDirectory":{"grpc":{"address":"","keepAlive":{"permitWithoutStream":true,"time":"10s","timeout":"20s"},"recvMsgSize":4194304,"sendMsgSize":4194304,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}}}}` | For complete grpc-gateway service configuration see [plgd/grpc-gateway](https://github.com/plgd-dev/hub/tree/main/grpc-gateway) | @@ -430,11 +435,12 @@ global: | httpgateway.service.targetPort | string | `"http"` | Target port | | httpgateway.service.type | string | `"ClusterIP"` | | | httpgateway.tolerations | object | `{}` | Toleration definition | -| httpgateway.ui | object | `{"directory":"/usr/local/var/www","enabled":true,"theme":"","webConfiguration":{"deviceOAuthClient":{"audience":null,"clientID":null,"providerName":null,"scopes":[]},"httpGatewayAddress":"","webOAuthClient":{"audience":"","clientID":"","scopes":[]}}}` | For complete http-gateway service configuration see [plgd/http-gateway](https://github.com/plgd-dev/hub/tree/main/http-gateway) | +| httpgateway.ui | object | `{"directory":"/usr/local/var/www","enabled":true,"theme":"","webConfiguration":{"deviceOAuthClient":{"audience":null,"clientID":null,"providerName":null,"scopes":[]},"deviceProvisioningService":"","httpGatewayAddress":"","visibility":{"mainSidebar":{"apiTokens":false,"certificates":true,"chatRoom":true,"configuration":true,"dashboard":false,"deviceFirmwareUpdate":false,"deviceLogs":false,"deviceProvisioning":true,"devices":true,"docs":true,"integrations":false,"pendingCommands":true,"remoteClients":true,"schemaHub":false}},"webOAuthClient":{"audience":"","clientID":"","scopes":[]}}}` | For complete http-gateway service configuration see [plgd/http-gateway](https://github.com/plgd-dev/hub/tree/main/http-gateway) | | httpgateway.uiDomain | string | `nil` | Domain for UI Default: {{ global.domain }} | | identitystore.affinity | object | `{}` | Affinity definition | | identitystore.apis | object | `{"grpc":{"address":null,"authorization":{"audience":null,"authority":null,"http":{"idleConnTimeout":"30s","maxConnsPerHost":32,"maxIdleConns":16,"maxIdleConnsPerHost":16,"timeout":"10s","tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":true}},"ownerClaim":null},"enforcementPolicy":{"minTime":"5s","permitWithoutStream":true},"keepAlive":{"maxConnectionAge":"0s","maxConnectionAgeGrace":"0s","maxConnectionIdle":"0s","time":"2h","timeout":"20s"},"recvMsgSize":4194304,"sendMsgSize":4194304,"tls":{"caPool":null,"certFile":null,"clientCertificateRequired":true,"keyFile":null}}}` | For complete identity service configuration see [plgd/identity](https://github.com/plgd-dev/hub/tree/main/identity) | -| identitystore.clients | object | `{"eventBus":{"nats":{"flusherTimeout":"30s","jetstream":false,"tls":{"useSystemCAPool":false},"url":""}},"storage":{"cqlDB":{"connectTimeout":"10s","hosts":[],"keyspace":{"create":true,"name":"plgdhub","replication":{"class":"SimpleStrategy","replication_factor":1}},"numConnections":16,"table":"deviceOwners","tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}},"mongoDB":{"database":"ownersDevices","maxConnIdleTime":"4m0s","maxPoolSize":16,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"uri":null},"use":"mongoDB"}}` | For complete identity service configuration see [plgd/authorization](https://github.com/plgd-dev/hub/tree/main/identity) | +| identitystore.clients | object | `{"eventBus":{"nats":{"flusherTimeout":"30s","jetstream":false,"tls":{"useSystemCAPool":false},"url":""}},"storage":{"cqlDB":{"connectTimeout":"10s","hosts":[],"keyspace":{"create":true,"name":"plgdhub","replication":{"class":"SimpleStrategy","replication_factor":1}},"numConnections":16,"port":9142,"reconnectionPolicy":{"constant":{"interval":"3s","maxRetries":3}},"table":"deviceOwners","tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"useHostnameResolution":true},"mongoDB":{"database":"ownersDevices","maxConnIdleTime":"4m0s","maxPoolSize":16,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"uri":null},"use":"mongoDB"}}` | For complete identity service configuration see [plgd/authorization](https://github.com/plgd-dev/hub/tree/main/identity) | +| identitystore.clients.storage.cqlDB.useHostnameResolution | bool | `true` | Resolve IP address to hostname before validate certificate. If false, the TLS validator will use ip/hostname advertised by the Cassandra node. | | identitystore.config | object | `{"fileName":"service.yaml","mountPath":"/config","volume":"config"}` | yaml configuration | | identitystore.config.fileName | string | `"service.yaml"` | File name | | identitystore.config.mountPath | string | `"/config"` | Service configuration mount path | @@ -553,8 +559,8 @@ global: | mockoauthserver.service.targetPort | string | `"http"` | Target port | | mockoauthserver.service.type | string | `"ClusterIP"` | | | mockoauthserver.tolerations | object | `{}` | Toleration definition | -| mongodb | object | `{"arbiter":{"enabled":false},"architecture":"replicaset","auth":{"enabled":false},"customLivenessProbe":{"exec":{"command":["/bin/bash","-c","/certs/livenessProbe.sh"]},"failureThreshold":6,"initialDelaySeconds":30,"periodSeconds":20,"successThreshold":1,"timeoutSeconds":10},"customReadinessProbe":{"exec":{"command":["bash","-ec","TLS_OPTIONS='--tls --tlsCertificateKeyFile=/certs/cert.pem --tlsCAFile=/certs/ca.pem'\n/certs/mongo $TLS_OPTIONS --eval 'db.hello().isWritablePrimary || db.hello().secondary' | grep -q 'true'\n"]},"failureThreshold":6,"initialDelaySeconds":10,"periodSeconds":20,"successThreshold":1,"timeoutSeconds":10},"enabled":true,"extraEnvVars":[{"name":"MONGODB_EXTRA_FLAGS","value":"--tlsMode=requireTLS --tlsCertificateKeyFile=/certs/cert.pem --tlsCAFile=/certs/ca.pem"},{"name":"MONGODB_CLIENT_EXTRA_FLAGS","value":"--tls --tlsCertificateKeyFile=/certs/cert.pem --tlsCAFile=/certs/ca.pem"}],"extraVolumeMounts":[{"mountPath":"/certs","name":"mongodb-crt"},{"mountPath":"/certs-original","name":"mongodb-cm-crt"}],"extraVolumes":[{"emptyDir":{},"name":"mongodb-crt"},{"name":"mongodb-cm-crt","secret":{"secretName":"mongodb-cm-crt"}}],"fullnameOverride":"mongodb","image":{"debug":true,"net":{"port":27017}},"initContainers":[{"command":["sh","-c","/bin/bash <<'EOF'\n#!/bin/bash\ncp /opt/bitnami/mongodb/bin/mongo /certs/mongo\necho '\nINIT=0\nwhile [[ $# -gt 0 ]]; do\n case $1 in\n --init)\n INIT=1\n shift\n ;;\n esac\ndone\n\nCERT_CRT=/certs-original/tls.crt\nCERT_SHA256=/certs/cert.sha256.$(sha256sum -z ${CERT_CRT} | cut -d \" \" -f 1)\nCA=/certs-original/ca.crt\nCA_SHA256=/certs/ca.sha256.$(sha256sum -z ${CA} | cut -d \" \" -f 1)\nROTATE_CERTIFICATES=0\nif [ ! -f ${CERT_SHA256} ]; then\n rm -f /certs/cert.sha256.*\n cat ${CERT_CRT} > /certs/cert.pem\n cat /certs-original/tls.key >> /certs/cert.pem\n touch ${CERT_SHA256}\n ROTATE_CERTIFICATES=1\nfi\n\nif [ ! -f ${CA_SHA256} ]; then\n rm -f /certs/ca.sha256.*\n cp ${CA} /certs/ca.pem\n touch ${CA_SHA256}\n ROTATE_CERTIFICATES=1\nfi\n\nif [ \"${INIT}\" == \"1\" ]; then\n exit 0\nfi\n\nif [ \"${ROTATE_CERTIFICATES}\" == \"1\" ]; then\n echo \"Rotating certificates\"\n /certs/mongo --tls --tlsCertificateKeyFile=/certs/cert.pem --tlsCAFile=/certs/ca.pem --eval db.adminCommand\\(\"{rotateCertificates: 1, message: \\\"Rotating certificates\\\"}\"\\)\nelse\n echo \"Ping database\"\n /certs/mongo --tls --tlsCertificateKeyFile=/certs/cert.pem --tlsCAFile=/certs/ca.pem --eval db.adminCommand\\(\\\"ping\\\"\\)\nfi\n' > /certs/livenessProbe.sh\nchmod u+x /certs/livenessProbe.sh\n/certs/livenessProbe.sh --init\nEOF\n"],"image":"docker.io/bitnami/mongodb:5.0.10-debian-11-r3","imagePullPolicy":"IfNotPresent","name":"mongo-binary","volumeMounts":[{"mountPath":"/certs","name":"mongodb-crt"},{"mountPath":"/certs-original","name":"mongodb-cm-crt"}]}],"livenessProbe":{"enabled":false},"persistence":{"enabled":true},"readinessProbe":{"enabled":false},"replicaCount":3,"replicaSetName":"rs0","tls":{"enabled":false}}` | External mongodb-replica dependency setup | -| nats | object | `{"cluster":{"enabled":false,"noAdvertise":false},"enabled":true,"leafnodes":{"enabled":false,"noAdvertise":false},"nats":{"tls":{"ca":"ca.crt","cert":"tls.crt","key":"tls.key","secret":{"name":"nats-service-crt"},"verify":true}},"natsbox":{"enabled":false},"reloader":{"image":"ghcr.io/plgd-dev/hub/nats-server-config-reloader:vnext","pullPolicy":"Always"}}` | External nats dependency setup | +| mongodb | object | `{"arbiter":{"enabled":false},"architecture":"replicaset","auth":{"enabled":false},"customLivenessProbe":{"exec":{"command":["/bin/bash","-c","/certs/livenessProbe.sh"]},"failureThreshold":6,"initialDelaySeconds":30,"periodSeconds":20,"successThreshold":1,"timeoutSeconds":10},"customReadinessProbe":{"exec":{"command":["bash","-ec","TLS_OPTIONS='--tls --tlsCertificateKeyFile=/certs/cert.pem --tlsCAFile=/certs/ca.pem'\n/certs/mongo $TLS_OPTIONS --eval 'db.hello().isWritablePrimary || db.hello().secondary' | grep -q 'true'\n"]},"failureThreshold":6,"initialDelaySeconds":10,"periodSeconds":20,"successThreshold":1,"timeoutSeconds":10},"enabled":true,"extraEnvVars":[{"name":"MONGODB_EXTRA_FLAGS","value":"--tlsMode=requireTLS --tlsCertificateKeyFile=/certs/cert.pem --tlsCAFile=/certs/ca.pem"},{"name":"MONGODB_CLIENT_EXTRA_FLAGS","value":"--tls --tlsCertificateKeyFile=/certs/cert.pem --tlsCAFile=/certs/ca.pem"}],"extraVolumeMounts":[{"mountPath":"/certs","name":"mongodb-crt"},{"mountPath":"/certs-original","name":"mongodb-cm-crt"}],"extraVolumes":[{"emptyDir":{},"name":"mongodb-crt"},{"name":"mongodb-cm-crt","secret":{"secretName":"mongodb-cm-crt"}}],"fullnameOverride":"mongodb","image":{"debug":true},"initContainers":[{"command":["sh","-c","/bin/bash <<'EOF'\n#!/bin/bash\ncp /opt/bitnami/mongodb/bin/mongo /certs/mongo\necho '\nINIT=0\nwhile [[ $# -gt 0 ]]; do\n case $1 in\n --init)\n INIT=1\n shift\n ;;\n esac\ndone\n\nCERT_CRT=/certs-original/tls.crt\nCERT_SHA256=/certs/cert.sha256.$(sha256sum -z ${CERT_CRT} | cut -d \" \" -f 1)\nCA=/certs-original/ca.crt\nCA_SHA256=/certs/ca.sha256.$(sha256sum -z ${CA} | cut -d \" \" -f 1)\nROTATE_CERTIFICATES=0\nif [ ! -f ${CERT_SHA256} ]; then\n rm -f /certs/cert.sha256.*\n cat ${CERT_CRT} > /certs/cert.pem\n cat /certs-original/tls.key >> /certs/cert.pem\n touch ${CERT_SHA256}\n ROTATE_CERTIFICATES=1\nfi\n\nif [ ! -f ${CA_SHA256} ]; then\n rm -f /certs/ca.sha256.*\n cp ${CA} /certs/ca.pem\n touch ${CA_SHA256}\n ROTATE_CERTIFICATES=1\nfi\n\nif [ \"${INIT}\" == \"1\" ]; then\n exit 0\nfi\n\nif [ \"${ROTATE_CERTIFICATES}\" == \"1\" ]; then\n echo \"Rotating certificates\"\n /certs/mongo --tls --tlsCertificateKeyFile=/certs/cert.pem --tlsCAFile=/certs/ca.pem --eval db.adminCommand\\(\"{rotateCertificates: 1, message: \\\"Rotating certificates\\\"}\"\\)\nelse\n echo \"Ping database\"\n /certs/mongo --tls --tlsCertificateKeyFile=/certs/cert.pem --tlsCAFile=/certs/ca.pem --eval db.adminCommand\\(\\\"ping\\\"\\)\nfi\n' > /certs/livenessProbe.sh\nchmod u+x /certs/livenessProbe.sh\n/certs/livenessProbe.sh --init\nEOF\n"],"image":"docker.io/bitnami/mongodb:5.0.10-debian-11-r3","imagePullPolicy":"IfNotPresent","name":"mongo-binary","volumeMounts":[{"mountPath":"/certs","name":"mongodb-crt"},{"mountPath":"/certs-original","name":"mongodb-cm-crt"}]}],"livenessProbe":{"enabled":false},"persistence":{"enabled":true},"readinessProbe":{"enabled":false},"replicaCount":3,"replicaSetName":"rs0","tls":{"enabled":false}}` | External mongodb-replica dependency setup | +| nats | object | `{"config":{"nats":{"tls":{"enabled":true,"merge":{"verify":true},"secretName":"nats-service-crt"}}},"enabled":true,"monitor":{"enabled":false},"natsBox":{"enabled":false},"tlsCA":{"enabled":true,"secretName":"nats-service-crt"}}` | External nats dependency setup | | resourceaggregate.affinity | object | `{}` | Affinity definition | | resourceaggregate.apis.grpc.address | string | `nil` | | | resourceaggregate.apis.grpc.authorization.audience | string | `nil` | | @@ -583,7 +589,8 @@ global: | resourceaggregate.apis.grpc.tls.certFile | string | `nil` | | | resourceaggregate.apis.grpc.tls.clientCertificateRequired | bool | `true` | | | resourceaggregate.apis.grpc.tls.keyFile | string | `nil` | | -| resourceaggregate.clients | object | `{"eventBus":{"nats":{"flusherTimeout":"30s","jetstream":false,"pendingLimits":{"bytesLimit":"67108864","msgLimit":524288},"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"url":null}},"eventStore":{"cqlDB":{"connectTimeout":"10s","hosts":[],"keyspace":{"create":true,"name":"plgdhub","replication":{"class":"SimpleStrategy","replication_factor":1}},"numConnections":16,"table":"events","tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}},"defaultCommandTimeToLive":null,"mongoDB":{"batchSize":128,"database":"eventStore","maxConnIdleTime":"4m0s","maxPoolSize":16,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"uri":null},"occMaxRetry":8,"use":"mongoDB"},"identityStore":{"grpc":{"address":null,"keepAlive":{"permitWithoutStream":true,"time":"10s","timeout":"20s"},"recvMsgSize":4194304,"sendMsgSize":4194304,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}}}}` | For complete resource-aggregate service configuration see [plgd/resource-aggregate](https://github.com/plgd-dev/hub/tree/main/resource-aggregate) | +| resourceaggregate.clients | object | `{"eventBus":{"nats":{"flusherTimeout":"30s","jetstream":false,"pendingLimits":{"bytesLimit":"67108864","msgLimit":524288},"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"url":null}},"eventStore":{"cqlDB":{"connectTimeout":"10s","hosts":[],"keyspace":{"create":true,"name":"plgdhub","replication":{"class":"SimpleStrategy","replication_factor":1}},"numConnections":16,"port":9142,"reconnectionPolicy":{"constant":{"interval":"3s","maxRetries":3}},"table":"events","tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"useHostnameResolution":true},"defaultCommandTimeToLive":null,"mongoDB":{"batchSize":128,"database":"eventStore","maxConnIdleTime":"4m0s","maxPoolSize":16,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"uri":null},"occMaxRetry":8,"use":"mongoDB"},"identityStore":{"grpc":{"address":null,"keepAlive":{"permitWithoutStream":true,"time":"10s","timeout":"20s"},"recvMsgSize":4194304,"sendMsgSize":4194304,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}}}}` | For complete resource-aggregate service configuration see [plgd/resource-aggregate](https://github.com/plgd-dev/hub/tree/main/resource-aggregate) | +| resourceaggregate.clients.eventStore.cqlDB.useHostnameResolution | bool | `true` | Resolve IP address to hostname before validate certificate. If false, the TLS validator will use ip/hostname advertised by the Cassandra node. | | resourceaggregate.config | object | `{"fileName":"service.yaml","mountPath":"/config","volume":"config"}` | Service configuration | | resourceaggregate.config.fileName | string | `"service.yaml"` | Service configuration file name | | resourceaggregate.config.mountPath | string | `"/config"` | Configuration mount path | @@ -636,7 +643,8 @@ global: | resourceaggregate.tolerations | object | `{}` | Toleration definition | | resourcedirectory.affinity | object | `{}` | Affinity definition | | resourcedirectory.apis | object | `{"grpc":{"address":null,"authorization":{"audience":null,"authority":null,"http":{"idleConnTimeout":"30s","maxConnsPerHost":32,"maxIdleConns":16,"maxIdleConnsPerHost":16,"timeout":"10s","tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":true}},"ownerClaim":null},"enforcementPolicy":{"minTime":"5s","permitWithoutStream":true},"keepAlive":{"maxConnectionAge":"0s","maxConnectionAgeGrace":"0s","maxConnectionIdle":"0s","time":"2h","timeout":"20s"},"ownerCacheExpiration":"1m","recvMsgSize":4194304,"sendMsgSize":4194304,"tls":{"caPool":null,"certFile":null,"clientCertificateRequired":true,"keyFile":null}}}` | For complete resource-directory service configuration see [plgd/resource-directory](https://github.com/plgd-dev/hub/tree/main/resource-directory) | -| resourcedirectory.clients | object | `{"eventBus":{"goPoolSize":16,"nats":{"pendingLimits":{"bytesLimit":"67108864","msgLimit":"524288"},"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"url":""}},"eventStore":{"cacheExpiration":"20m","cqlDB":{"connectTimeout":"10s","hosts":[],"keyspace":{"create":true,"name":"plgdhub","replication":{"class":"SimpleStrategy","replication_factor":1}},"numConnections":16,"table":"events","tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}},"mongoDB":{"batchSize":128,"database":"eventStore","maxConnIdleTime":"4m0s","maxPoolSize":16,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"uri":""},"use":"mongoDB"},"identityStore":{"cacheExpiration":"1m","grpc":{"address":"","keepAlive":{"permitWithoutStream":true,"time":"10s","timeout":"20s"},"recvMsgSize":4194304,"sendMsgSize":4194304,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}},"oauth":{"audience":"","clientID":null,"clientSecret":null,"http":{"idleConnTimeout":"30s","maxConnsPerHost":32,"maxIdleConns":16,"maxIdleConnsPerHost":16,"timeout":"10s","tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}},"scopes":[],"tokenURL":"","verifyServiceTokenFrequency":"10s"},"ownerClaim":null,"pullFrequency":"15s"}}` | For complete resource-directory service configuration see [plgd/resource-directory](https://github.com/plgd-dev/hub/tree/main/resource-directory) | +| resourcedirectory.clients | object | `{"eventBus":{"goPoolSize":16,"nats":{"pendingLimits":{"bytesLimit":"67108864","msgLimit":"524288"},"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"url":""}},"eventStore":{"cacheExpiration":"20m","cqlDB":{"connectTimeout":"10s","hosts":[],"keyspace":{"create":true,"name":"plgdhub","replication":{"class":"SimpleStrategy","replication_factor":1}},"numConnections":16,"port":9142,"reconnectionPolicy":{"constant":{"interval":"3s","maxRetries":3}},"table":"events","tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"useHostnameResolution":true},"mongoDB":{"batchSize":128,"database":"eventStore","maxConnIdleTime":"4m0s","maxPoolSize":16,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false},"uri":""},"use":"mongoDB"},"identityStore":{"cacheExpiration":"1m","grpc":{"address":"","keepAlive":{"permitWithoutStream":true,"time":"10s","timeout":"20s"},"recvMsgSize":4194304,"sendMsgSize":4194304,"tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}},"oauth":{"audience":"","clientID":null,"clientSecret":null,"http":{"idleConnTimeout":"30s","maxConnsPerHost":32,"maxIdleConns":16,"maxIdleConnsPerHost":16,"timeout":"10s","tls":{"caPool":null,"certFile":null,"keyFile":null,"useSystemCAPool":false}},"scopes":[],"tokenURL":"","verifyServiceTokenFrequency":"10s"},"ownerClaim":null,"pullFrequency":"15s"}}` | For complete resource-directory service configuration see [plgd/resource-directory](https://github.com/plgd-dev/hub/tree/main/resource-directory) | +| resourcedirectory.clients.eventStore.cqlDB.useHostnameResolution | bool | `true` | Resolve IP address to hostname before validate certificate. If false, the TLS validator will use ip/hostname advertised by the Cassandra node. | | resourcedirectory.config | object | `{"fileName":"service.yaml","mountPath":"/config","volume":"config"}` | Service configuration | | resourcedirectory.config.fileName | string | `"service.yaml"` | Service configuration file | | resourcedirectory.config.mountPath | string | `"/config"` | Configuration mount path | @@ -687,9 +695,23 @@ global: | resourcedirectory.service.targetPort | string | `"grpc"` | Target port | | resourcedirectory.service.type | string | `"ClusterIP"` | resource-directory service type | | resourcedirectory.tolerations | object | `{}` | Toleration definition | -| scylla.datacenter | string | `"dc1"` | | -| scylla.enabled | bool | `false` | | +| scylla.datacenter | string | `"dc-1"` | | +| scylla.enabled | bool | `false` | Enable scylla service. Required scylla operator: https://github.com/scylladb/scylla-operator/blob/master/docs/source/generic.md#deploy-scylla-operator | +| scylla.racks[0].members | int | `3` | | +| scylla.racks[0].name | string | `"dc-1a"` | | +| scylla.racks[0].resources.limits.cpu | int | `1` | | +| scylla.racks[0].resources.limits.memory | string | `"4Gi"` | | +| scylla.racks[0].resources.requests.cpu | int | `1` | | +| scylla.racks[0].resources.requests.memory | string | `"4Gi"` | | +| scylla.racks[0].scyllaConfig | string | `"scylla-cfg"` | | +| scylla.racks[0].storage.capacity | string | `"10Gi"` | | +| scylla.racks[0].volumeMounts[0].mountPath | string | `"/certs"` | | +| scylla.racks[0].volumeMounts[0].name | string | `"scylla-certs-volume"` | | +| scylla.racks[0].volumes[0].name | string | `"scylla-certs-volume"` | | +| scylla.racks[0].volumes[0].secret.secretName | string | `"scylla-dc-1a-crt"` | | +| scylla.scyllaImage.tag | string | `"5.2.9"` | | +| scylla.sysctls[0] | string | `"fs.aio-max-nr=2097152"` | | ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.3](https://github.com/norwoodj/helm-docs/releases/v1.11.3) +Autogenerated from chart metadata using [helm-docs v1.12.0](https://github.com/norwoodj/helm-docs/releases/v1.12.0) diff --git a/charts/plgd-hub/templates/certs/internal/nats-crt.yaml b/charts/plgd-hub/templates/certs/internal/nats-crt.yaml index d425bcb18..a800f32de 100644 --- a/charts/plgd-hub/templates/certs/internal/nats-crt.yaml +++ b/charts/plgd-hub/templates/certs/internal/nats-crt.yaml @@ -1,14 +1,14 @@ -{{- if and .Values.nats.enabled .Values.certmanager.enabled }} +{{- if and .Values.nats.enabled .Values.certmanager.enabled .Values.nats.config.nats.tls.enabled }} {{- $natsServiceName := printf "%s-nats" ( include "nats.fullname" . ) }} apiVersion: cert-manager.io/v1 kind: Certificate metadata: - name: {{ .Values.nats.nats.tls.secret.name }} + name: {{ .Values.nats.config.nats.tls.secretName }} namespace: {{ .Release.Namespace }} labels: {{- include "plgd-hub.labels" . | nindent 4 }} spec: - secretName: {{ .Values.nats.nats.tls.secret.name }} + secretName: {{ .Values.nats.config.nats.tls.secretName }} privateKey: algorithm: {{ .Values.certmanager.internal.cert.key.algorithm | default .Values.certmanager.default.cert.key.algorithm }} size: {{ .Values.certmanager.internal.cert.key.size | default .Values.certmanager.default.cert.key.size }} diff --git a/charts/plgd-hub/values.yaml b/charts/plgd-hub/values.yaml index 4d9a252f0..811daff00 100644 --- a/charts/plgd-hub/values.yaml +++ b/charts/plgd-hub/values.yaml @@ -56,25 +56,20 @@ extraDeploy: # -- External nats dependency setup nats: enabled: true - nats: - tls: - secret: - name: nats-service-crt - ca: ca.crt - cert: tls.crt - key: tls.key - verify: true - cluster: - enabled: false - noAdvertise: false - leafnodes: + tlsCA: + enabled: true + secretName: nats-service-crt + config: + nats: + tls: + enabled: true + secretName: nats-service-crt + merge: + verify: true + natsBox: enabled: false - noAdvertise: false - natsbox: + monitor: enabled: false - reloader: - image: ghcr.io/plgd-dev/hub/nats-server-config-reloader:vnext - pullPolicy: Always # -- External mongodb-replica dependency setup @@ -92,8 +87,6 @@ mongodb: enabled: false image: debug: true - net: - port: 27017 tls: enabled: false extraEnvVars: diff --git a/cloud2cloud-connector/events/event.go b/cloud2cloud-connector/events/event.go index 0d5379041..e8cccab97 100644 --- a/cloud2cloud-connector/events/event.go +++ b/cloud2cloud-connector/events/event.go @@ -4,6 +4,7 @@ import ( "crypto/hmac" "crypto/sha256" "encoding/hex" + "errors" "fmt" "net/http" "strconv" @@ -51,7 +52,7 @@ func invalidKey(key string) string { } func invalidKeyError(key string) error { - return fmt.Errorf(invalidKey(key)) + return errors.New(invalidKey(key)) } func invalidKeyValueError(key string, value interface{}, err error) error { @@ -120,7 +121,7 @@ func ParseEventHeader(r *http.Request) (h EventHeader, _ error) { if r.Method == "POST" && v != "" { acceptEncoding = strings.Split(v, ",") if len(acceptEncoding) != 1 { - return h, invalidKeyValueError(AcceptEncodingKey, acceptEncoding, fmt.Errorf("more than 1")) + return h, invalidKeyValueError(AcceptEncodingKey, acceptEncoding, errors.New("more than 1")) } } diff --git a/cloud2cloud-connector/service/addLinkedAccount.go b/cloud2cloud-connector/service/addLinkedAccount.go index 83b0ae089..a79e0ffdb 100644 --- a/cloud2cloud-connector/service/addLinkedAccount.go +++ b/cloud2cloud-connector/service/addLinkedAccount.go @@ -4,6 +4,7 @@ import ( "context" "crypto/rand" "encoding/base64" + "errors" "fmt" "net/http" "time" @@ -28,7 +29,7 @@ func (h *LinkedCloudHandler) Handle(ctx context.Context, iter store.LinkedCloudI h.linkedCloud = s return iter.Err() } - return fmt.Errorf("not found") + return errors.New("not found") } func generateRandomString(n int) (string, error) { @@ -42,14 +43,14 @@ func generateRandomString(n int) (string, error) { func (rh *RequestHandler) handleOAuth(w http.ResponseWriter, r *http.Request, linkedAccount store.LinkedAccount, linkedCloud store.LinkedCloud) (int, error) { t, err := generateRandomString(32) if err != nil { - return http.StatusInternalServerError, fmt.Errorf("cannot generate token") + return http.StatusInternalServerError, errors.New("cannot generate token") } _, loaded := rh.provisionCache.LoadOrStore(t, cache.NewElement(ProvisionCacheData{ linkedAccount: linkedAccount, linkedCloud: linkedCloud, }, time.Now().Add(CacheExpiration), nil)) if loaded { - return http.StatusInternalServerError, fmt.Errorf("cannot store key - collision") + return http.StatusInternalServerError, errors.New("cannot store key - collision") } if !linkedAccount.Data.HasOrigin() { @@ -86,7 +87,7 @@ func (rh *RequestHandler) addLinkedAccount(w http.ResponseWriter, r *http.Reques UserID: userID, } if linkedAccount.LinkedCloudID == "" { - return http.StatusBadRequest, fmt.Errorf("invalid cloud_id") + return http.StatusBadRequest, errors.New("invalid cloud_id") } return rh.handleOAuth(w, r, linkedAccount, linkedCloud) } diff --git a/cloud2cloud-connector/service/deviceSubscriptionHandlers.go b/cloud2cloud-connector/service/deviceSubscriptionHandlers.go index 2f9b0276d..25a700ea7 100644 --- a/cloud2cloud-connector/service/deviceSubscriptionHandlers.go +++ b/cloud2cloud-connector/service/deviceSubscriptionHandlers.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "sync/atomic" "time" @@ -41,15 +42,15 @@ func (h deviceSubscriptionHandlers) RetrieveResource(ctx context.Context, event } func (h deviceSubscriptionHandlers) DeleteResource(context.Context, *raEvents.ResourceDeletePending) error { - return fmt.Errorf(NOT_SUPPORTED_ERR) + return errors.New(NOT_SUPPORTED_ERR) } func (h deviceSubscriptionHandlers) CreateResource(context.Context, *raEvents.ResourceCreatePending) error { - return fmt.Errorf(NOT_SUPPORTED_ERR) + return errors.New(NOT_SUPPORTED_ERR) } func (h deviceSubscriptionHandlers) UpdateDeviceMetadata(context.Context, *raEvents.DeviceMetadataUpdatePending) error { - return fmt.Errorf(NOT_SUPPORTED_ERR) + return errors.New(NOT_SUPPORTED_ERR) } func (h deviceSubscriptionHandlers) OnDeviceSubscriberReconnectError(err error) { @@ -115,7 +116,7 @@ func (c *DevicesSubscription) Add(ctx context.Context, deviceID string, linkedAc return retrieveResource(ctx, c.tracerProvider, c.raClient, val, linkedAccount, linkedCloud) }, onError: func(err error) { - log.Errorf("device %v subscription(ResourceUpdatePending, ResourceRetrievePending) was closed", deviceID) + log.Errorf("device %v subscription(ResourceUpdatePending, ResourceRetrievePending) was closed: %w", deviceID, err) c.data.Delete(getKey(linkedAccount.UserID, deviceID)) }, }) diff --git a/cloud2cloud-connector/service/devicesSubscription.go b/cloud2cloud-connector/service/devicesSubscription.go index 439f2a8e4..f68b47a6c 100644 --- a/cloud2cloud-connector/service/devicesSubscription.go +++ b/cloud2cloud-connector/service/devicesSubscription.go @@ -135,7 +135,7 @@ func (s *SubscriptionManager) handleDevicesUnregistered(ctx context.Context, sub if err != nil { errors = multierror.Append(errors, fmt.Errorf("cannot remove device %v from user: %w", device.ID, err)) } - if err == nil && len(resp.DeviceIds) != 1 { + if err == nil && len(resp.GetDeviceIds()) != 1 { errors = multierror.Append(errors, fmt.Errorf("cannot remove device %v from user", device.ID)) } err = s.devicesSubscription.Delete(userID, device.ID) diff --git a/cloud2cloud-connector/service/getDevices_test.go b/cloud2cloud-connector/service/getDevices_test.go index 1f57dcfcc..db3ee190b 100644 --- a/cloud2cloud-connector/service/getDevices_test.go +++ b/cloud2cloud-connector/service/getDevices_test.go @@ -70,7 +70,7 @@ func testRequestHandlerGetDevices(t *testing.T, events store.Events) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(c2cConnectorTest.GRPC_GATEWAY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(c2cConnectorTest.GRPC_GATEWAY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -94,11 +94,12 @@ func testRequestHandlerGetDevices(t *testing.T, events store.Events) { break } require.NoError(t, err) - assert.NotEmpty(t, dev.ProtocolIndependentId) + assert.NotEmpty(t, dev.GetProtocolIndependentId()) dev.ProtocolIndependentId = "" if dev.GetMetadata().GetConnection() != nil { dev.GetMetadata().GetConnection().Id = "" dev.GetMetadata().GetConnection().ConnectedAt = 0 + dev.GetMetadata().GetConnection().LocalEndpoints = nil } if dev.GetMetadata().GetTwinSynchronization() != nil { dev.GetMetadata().GetTwinSynchronization().CommandMetadata = nil diff --git a/cloud2cloud-connector/service/oauthCallback.go b/cloud2cloud-connector/service/oauthCallback.go index d4522cd84..890a365bb 100644 --- a/cloud2cloud-connector/service/oauthCallback.go +++ b/cloud2cloud-connector/service/oauthCallback.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "net/http" @@ -43,7 +44,7 @@ func (rh *RequestHandler) oAuthCallback(w http.ResponseWriter, r *http.Request) cacheData := rh.provisionCache.Load(state) if cacheData == nil { - return http.StatusBadRequest, fmt.Errorf("invalid/expired OAuth state") + return http.StatusBadRequest, errors.New("invalid/expired OAuth state") } rh.provisionCache.Delete(state) data := cacheData.Data() diff --git a/cloud2cloud-connector/service/pull.go b/cloud2cloud-connector/service/pull.go index 3bc4589de..ca97e02e2 100644 --- a/cloud2cloud-connector/service/pull.go +++ b/cloud2cloud-connector/service/pull.go @@ -70,7 +70,7 @@ func getOwnerDevices(ctx context.Context, isClient pbIS.IdentityStoreClient) (ma continue } - ownerDevices[device.DeviceId] = true + ownerDevices[device.GetDeviceId()] = true } return ownerDevices, nil } @@ -193,7 +193,7 @@ func (p *pullDevicesHandler) deleteDevice(ctx context.Context, userID, deviceID if err != nil { errors = multierror.Append(errors, fmt.Errorf("cannot delete device %v: %w", deviceID, err)) } - if err == nil && len(resp.DeviceIds) != 1 { + if err == nil && len(resp.GetDeviceIds()) != 1 { errors = multierror.Append(errors, fmt.Errorf("cannot remove device %v", deviceID)) } return errors.ErrorOrNil() diff --git a/cloud2cloud-connector/service/requestHandler.go b/cloud2cloud-connector/service/requestHandler.go index f8bfa780d..265cfe217 100644 --- a/cloud2cloud-connector/service/requestHandler.go +++ b/cloud2cloud-connector/service/requestHandler.go @@ -82,7 +82,7 @@ func NewHTTP(requestHandler *RequestHandler, authInterceptor kitNetHttp.Intercep r := router.NewRouter() r.StrictSlash(true) r.Use(kitNetHttp.CreateLoggingMiddleware(kitNetHttp.WithLogger(logger))) - r.Use(kitNetHttp.CreateAuthMiddleware(authInterceptor, func(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) { + r.Use(kitNetHttp.CreateAuthMiddleware(authInterceptor, func(_ context.Context, w http.ResponseWriter, r *http.Request, err error) { logAndWriteErrorResponse(fmt.Errorf("cannot process request on %v: %w", r.RequestURI, err), http.StatusUnauthorized, w) })) diff --git a/cloud2cloud-connector/service/retrieveResourceFromDevice_test.go b/cloud2cloud-connector/service/retrieveResourceFromDevice_test.go index 4f74d2905..80e41a20e 100644 --- a/cloud2cloud-connector/service/retrieveResourceFromDevice_test.go +++ b/cloud2cloud-connector/service/retrieveResourceFromDevice_test.go @@ -48,7 +48,7 @@ func testRequestHandlerGetResourceFromDevice(t *testing.T, events store.Events) }, }, wantContentType: message.AppOcfCbor.String(), - want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), "", map[string]interface{}{ + want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "name": "Light", "power": uint64(0), "state": false, @@ -62,7 +62,7 @@ func testRequestHandlerGetResourceFromDevice(t *testing.T, events store.Events) }, }, wantContentType: message.AppOcfCbor.String(), - want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceSwitchesHref, "", []map[interface{}]interface{}{ + want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "", []map[interface{}]interface{}{ { "href": test.TestResourceSwitchesInstanceHref(switchID), "if": []interface{}{interfaces.OC_IF_A, interfaces.OC_IF_BASELINE}, @@ -80,7 +80,7 @@ func testRequestHandlerGetResourceFromDevice(t *testing.T, events store.Events) }, }, wantContentType: message.AppOcfCbor.String(), - want: pbTest.MakeResourceRetrieved(t, deviceID, device.ResourceURI, "", map[string]interface{}{ + want: pbTest.MakeResourceRetrieved(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "di": deviceID, "dmv": "ocf.res.1.3.0", "icv": "ocf.2.0.5", @@ -107,7 +107,7 @@ func testRequestHandlerGetResourceFromDevice(t *testing.T, events store.Events) defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(c2cConnectorTest.GRPC_GATEWAY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(c2cConnectorTest.GRPC_GATEWAY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/cloud2cloud-connector/service/service.go b/cloud2cloud-connector/service/service.go index 2a2a53b94..5f4b786cc 100644 --- a/cloud2cloud-connector/service/service.go +++ b/cloud2cloud-connector/service/service.go @@ -125,8 +125,8 @@ func newStore(ctx context.Context, config pkgMongo.Config, fileWatcher *fsnotify return nil, nil, fmt.Errorf("cannot create mongodb subscription store: %w", err) } fl.AddFunc(func() { - if err := db.Close(ctx); err != nil { - log.Errorf("failed to close subscription store: %w", err) + if errC := db.Close(ctx); errC != nil { + log.Errorf("failed to close subscription store: %w", errC) } }) diff --git a/cloud2cloud-connector/service/store.go b/cloud2cloud-connector/service/store.go index 481469fc5..a7cf41bdc 100644 --- a/cloud2cloud-connector/service/store.go +++ b/cloud2cloud-connector/service/store.go @@ -2,7 +2,7 @@ package service import ( "context" - "fmt" + "errors" "github.com/plgd-dev/hub/v2/cloud2cloud-connector/store" "github.com/plgd-dev/hub/v2/pkg/log" @@ -128,7 +128,7 @@ func (s *Store) PullOutSubscription(subscripionID string) (SubscriptionData, boo func (s *Store) PullOutCloud(ctx context.Context, cloudID string) (*CloudData, error) { cloud, ok := s.cache.PullOutCloud(cloudID) if !ok { - return cloud, fmt.Errorf("not found") + return cloud, errors.New("not found") } return cloud, s.db.RemoveLinkedCloud(ctx, cloudID) } @@ -136,7 +136,7 @@ func (s *Store) PullOutCloud(ctx context.Context, cloudID string) (*CloudData, e func (s *Store) PullOutLinkedAccount(ctx context.Context, cloudID, linkedAccountID string) (*LinkedAccountData, error) { cloud, ok := s.cache.PullOutLinkedAccount(cloudID, linkedAccountID) if !ok { - return cloud, fmt.Errorf("not found") + return cloud, errors.New("not found") } return cloud, s.db.RemoveLinkedAccount(ctx, linkedAccountID) } diff --git a/cloud2cloud-connector/service/subscriptions.go b/cloud2cloud-connector/service/subscriptions.go index 7ae4ebaeb..d95a30792 100644 --- a/cloud2cloud-connector/service/subscriptions.go +++ b/cloud2cloud-connector/service/subscriptions.go @@ -107,13 +107,13 @@ func subscribe(ctx context.Context, tracerProvider trace.TracerProvider, href, c go func() { defer func() { - if err := w.Close(); err != nil { - log.Errorf("failed to close write pipe: %v", err) + if errC := w.Close(); errC != nil { + log.Errorf("failed to close write pipe: %w", errC) } }() - err := json.WriteTo(w, reqBody) - if err != nil { - log.Errorf("cannot encode %+v to json: %w", reqBody, err) + errW := json.WriteTo(w, reqBody) + if errW != nil { + log.Errorf("cannot encode %+v to json: %w", reqBody, errW) } }() httpResp, err := client.Do(req) @@ -212,7 +212,7 @@ func (s *SubscriptionManager) handleEvent(ctx context.Context, header events.Eve ctx = kitNetGrpc.CtxWithToken(ctx, subData.linkedAccount.Data.Origin().AccessToken.String()) if header.EventType == events.EventType_SubscriptionCanceled { - err := s.handleCancelEvent(header) + err = s.handleCancelEvent(header) if err != nil { return http.StatusGone, fmt.Errorf("cannot cancel subscription: %w", err) } diff --git a/cloud2cloud-connector/service/taskProcessor.go b/cloud2cloud-connector/service/taskProcessor.go index f38d018a0..497f284bb 100644 --- a/cloud2cloud-connector/service/taskProcessor.go +++ b/cloud2cloud-connector/service/taskProcessor.go @@ -150,9 +150,9 @@ func (h *TaskProcessor) Run(ctx context.Context, subscriptionManager *Subscripti for process { select { case e := <-h.tasksChan: - ctx, cancel := context.WithTimeout(ctx, h.timeout) + runctx, cancel := context.WithTimeout(ctx, h.timeout) defer cancel() - err := h.runTask(ctx, e, subscriptionManager) + err := h.runTask(runctx, e, subscriptionManager) if err != nil { log.Errorf("cannot process task %+v: %w", e, err) } diff --git a/cloud2cloud-connector/service/updateResource.go b/cloud2cloud-connector/service/updateResource.go index f00edaf23..fb53a7e78 100644 --- a/cloud2cloud-connector/service/updateResource.go +++ b/cloud2cloud-connector/service/updateResource.go @@ -40,12 +40,12 @@ func updateDeviceResource(ctx context.Context, tracerProvider trace.TracerProvid go func() { defer func() { if errC := w.Close(); errC != nil { - log.Errorf("failed to close write pipe: %v", errC) + log.Errorf("failed to close write pipe: %w", errC) } }() - _, err := w.Write(content) - if err != nil { - log.Errorf("cannot update content of device %v resource %v: %w", deviceID, href, err) + _, errW := w.Write(content) + if errW != nil { + log.Errorf("cannot update content of device %v resource %v: %w", deviceID, href, errW) } }() httpResp, err := client.Do(req) diff --git a/cloud2cloud-connector/service/updateResource_test.go b/cloud2cloud-connector/service/updateResource_test.go index 89fc58e6c..652cb58f6 100644 --- a/cloud2cloud-connector/service/updateResource_test.go +++ b/cloud2cloud-connector/service/updateResource_test.go @@ -54,8 +54,9 @@ func testRequestHandlerUpdateResource(t *testing.T, events store.Events) { Content: &commands.Content{ CoapContentFormat: -1, }, - Status: commands.Status_OK, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + Status: commands.Status_OK, + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, }, { @@ -77,8 +78,9 @@ func testRequestHandlerUpdateResource(t *testing.T, events store.Events) { Content: &commands.Content{ CoapContentFormat: -1, }, - Status: commands.Status_OK, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + Status: commands.Status_OK, + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, }, { @@ -100,8 +102,9 @@ func testRequestHandlerUpdateResource(t *testing.T, events store.Events) { Content: &commands.Content{ CoapContentFormat: -1, }, - Status: commands.Status_OK, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + Status: commands.Status_OK, + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, }, { @@ -137,7 +140,7 @@ func testRequestHandlerUpdateResource(t *testing.T, events store.Events) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(c2cConnectorTest.GRPC_GATEWAY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(c2cConnectorTest.GRPC_GATEWAY_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/cloud2cloud-connector/store/mongodb/linkedAccounts.go b/cloud2cloud-connector/store/mongodb/linkedAccounts.go index 77eb611fd..55414965c 100644 --- a/cloud2cloud-connector/store/mongodb/linkedAccounts.go +++ b/cloud2cloud-connector/store/mongodb/linkedAccounts.go @@ -14,21 +14,21 @@ const resLinkedAccountCName = "linkedAccounts" func validateLinkedAccount(sub store.LinkedAccount) error { if sub.ID == "" { - return fmt.Errorf("invalid ID") + return errors.New("invalid ID") } if sub.UserID == "" { - return fmt.Errorf("invalid UserID") + return errors.New("invalid UserID") } if sub.LinkedCloudID == "" { - return fmt.Errorf("invalid LinkedCloudID") + return errors.New("invalid LinkedCloudID") } origin := sub.Data.Origin() if origin.AccessToken == "" && origin.RefreshToken == "" { - return fmt.Errorf("invalid Data.OriginCloud.AccessToken and Data.OriginCloud.RefreshToken") + return errors.New("invalid Data.OriginCloud.AccessToken and Data.OriginCloud.RefreshToken") } target := sub.Data.Target() if target.AccessToken == "" && target.RefreshToken == "" { - return fmt.Errorf("invalid Data.TargetCloud.AccessToken and Data.TargetCloud.RefreshToken") + return errors.New("invalid Data.TargetCloud.AccessToken and Data.TargetCloud.RefreshToken") } return nil } @@ -59,21 +59,21 @@ func (s *Store) UpdateLinkedAccount(ctx context.Context, sub store.LinkedAccount return fmt.Errorf("cannot update linked account: %w", err) } if res.MatchedCount == 0 { - return fmt.Errorf("cannot update linked account: not found") + return errors.New("cannot update linked account: not found") } return nil } func (s *Store) RemoveLinkedAccount(ctx context.Context, linkedAccountID string) error { if linkedAccountID == "" { - return fmt.Errorf("cannot remove linked account: invalid linkedAccountID") + return errors.New("cannot remove linked account: invalid linkedAccountID") } res, err := s.Collection(resLinkedAccountCName).DeleteOne(ctx, bson.M{"_id": linkedAccountID}) if err != nil { return fmt.Errorf("cannot remove linked account: %w", err) } if res.DeletedCount == 0 { - return fmt.Errorf("cannot remove linked account: not found") + return errors.New("cannot remove linked account: not found") } return nil } diff --git a/cloud2cloud-connector/store/mongodb/linkedAccounts_test.go b/cloud2cloud-connector/store/mongodb/linkedAccounts_test.go index bcfd24f20..0bb3ed8e6 100644 --- a/cloud2cloud-connector/store/mongodb/linkedAccounts_test.go +++ b/cloud2cloud-connector/store/mongodb/linkedAccounts_test.go @@ -7,7 +7,6 @@ import ( "github.com/plgd-dev/hub/v2/cloud2cloud-connector/store" "github.com/plgd-dev/hub/v2/cloud2cloud-connector/test" "github.com/plgd-dev/hub/v2/pkg/security/oauth2" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -45,10 +44,10 @@ func TestStoreInsertLinkedAccount(t *testing.T) { t.Run(tt.name, func(t *testing.T) { err := s.InsertLinkedAccount(ctx, tt.args.sub) if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) + require.Error(t, err) + return } + require.NoError(t, err) }) } } @@ -107,10 +106,10 @@ func TestStoreUpdateLinkedAccount(t *testing.T) { t.Run(tt.name, func(t *testing.T) { err := s.UpdateLinkedAccount(ctx, tt.args.sub) if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) + require.Error(t, err) + return } + require.NoError(t, err) }) } } @@ -159,10 +158,10 @@ func TestStoreRemoveLinkedAccount(t *testing.T) { t.Run(tt.name, func(t *testing.T) { err := s.RemoveLinkedAccount(ctx, tt.args.linkedAccountID) if tt.wantErr { - assert.Error(t, err) + require.Error(t, err) return } - assert.NoError(t, err) + require.NoError(t, err) }) } } @@ -241,11 +240,11 @@ func TestStoreLoadLinkedAccounts(t *testing.T) { var h testLinkedAccountHandler err := s.LoadLinkedAccounts(ctx, tt.args.query, &h) if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equal(t, tt.want, h.accs) + require.Error(t, err) + return } + require.NoError(t, err) + require.Equal(t, tt.want, h.accs) }) } } diff --git a/cloud2cloud-connector/store/mongodb/linkedClouds.go b/cloud2cloud-connector/store/mongodb/linkedClouds.go index 48af42c9f..857249014 100644 --- a/cloud2cloud-connector/store/mongodb/linkedClouds.go +++ b/cloud2cloud-connector/store/mongodb/linkedClouds.go @@ -14,22 +14,22 @@ const resLinkedCloudCName = "LinkedCloud" func validateLinkedCloud(sub store.LinkedCloud) error { if sub.ID == "" { - return fmt.Errorf("cannot save linked cloud: invalid Id") + return errors.New("cannot save linked cloud: invalid Id") } if sub.Endpoint.URL == "" { - return fmt.Errorf("cannot save linked cloud: invalid URL") + return errors.New("cannot save linked cloud: invalid URL") } if sub.OAuth.ClientID == "" { - return fmt.Errorf("cannot save linked cloud: invalid ClientId") + return errors.New("cannot save linked cloud: invalid ClientId") } if sub.OAuth.ClientSecret == "" { - return fmt.Errorf("cannot save linked cloud: invalid ClientSecret") + return errors.New("cannot save linked cloud: invalid ClientSecret") } if sub.OAuth.AuthURL == "" { - return fmt.Errorf("cannot save linked cloud: invalid AuthUrl") + return errors.New("cannot save linked cloud: invalid AuthUrl") } if sub.OAuth.TokenURL == "" { - return fmt.Errorf("cannot save linked cloud: invalid TokenUrl") + return errors.New("cannot save linked cloud: invalid TokenUrl") } return nil } @@ -46,7 +46,7 @@ func (s *Store) UpdateLinkedCloud(ctx context.Context, sub store.LinkedCloud) er return fmt.Errorf("cannot save linked cloud: %w", err) } if res.MatchedCount == 0 { - return fmt.Errorf("cannot update linked cloud: not found") + return errors.New("cannot update linked cloud: not found") } return nil } @@ -67,7 +67,7 @@ func (s *Store) InsertLinkedCloud(ctx context.Context, sub store.LinkedCloud) er func (s *Store) RemoveLinkedCloud(ctx context.Context, linkedCloudID string) error { if linkedCloudID == "" { - return fmt.Errorf("cannot remove linked cloud: invalid LinkedCloudId") + return errors.New("cannot remove linked cloud: invalid LinkedCloudId") } res, err := s.Collection(resLinkedCloudCName).DeleteOne(ctx, bson.M{"_id": linkedCloudID}) @@ -75,7 +75,7 @@ func (s *Store) RemoveLinkedCloud(ctx context.Context, linkedCloudID string) err return fmt.Errorf("cannot remove linked cloud: %w", err) } if res.DeletedCount == 0 { - return fmt.Errorf("cannot remove linked cloud: not found") + return errors.New("cannot remove linked cloud: not found") } return nil } diff --git a/cloud2cloud-connector/store/mongodb/linkedClouds_test.go b/cloud2cloud-connector/store/mongodb/linkedClouds_test.go index a983ae00d..b1b68867a 100644 --- a/cloud2cloud-connector/store/mongodb/linkedClouds_test.go +++ b/cloud2cloud-connector/store/mongodb/linkedClouds_test.go @@ -7,7 +7,6 @@ import ( "github.com/plgd-dev/hub/v2/cloud2cloud-connector/store" "github.com/plgd-dev/hub/v2/cloud2cloud-connector/test" "github.com/plgd-dev/hub/v2/pkg/security/oauth2/oauth" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -85,10 +84,10 @@ func TestStoreUpdateLinkedCloud(t *testing.T) { t.Run(tt.name, func(t *testing.T) { err := s.UpdateLinkedCloud(ctx, tt.args.sub) if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) + require.Error(t, err) + return } + require.NoError(t, err) }) } } @@ -142,10 +141,10 @@ func TestStoreRemoveLinkedCloud(t *testing.T) { t.Run(tt.name, func(t *testing.T) { err := s.RemoveLinkedCloud(ctx, tt.args.LinkedCloudID) if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) + require.Error(t, err) + return } + require.NoError(t, err) }) } } @@ -242,11 +241,11 @@ func TestStoreLoadLinkedClouds(t *testing.T) { var h testLinkedCloudHandler err := s.LoadLinkedClouds(ctx, tt.args.query, &h) if tt.wantErr { - assert.Error(t, err) + require.Error(t, err) return } - assert.NoError(t, err) - assert.Equal(t, tt.want, h.lcs) + require.NoError(t, err) + require.Equal(t, tt.want, h.lcs) }) } } diff --git a/cloud2cloud-connector/store/mongodb/store.go b/cloud2cloud-connector/store/mongodb/store.go index eccf4c4b5..205661dd7 100644 --- a/cloud2cloud-connector/store/mongodb/store.go +++ b/cloud2cloud-connector/store/mongodb/store.go @@ -19,9 +19,7 @@ func NewStore(ctx context.Context, cfg pkgMongo.Config, tls *tls.Config, tracerP return nil, err } s := Store{m} - s.SetOnClear(func(c context.Context) error { - return s.clearDatabases(ctx) - }) + s.SetOnClear(s.clearDatabases) return &s, nil } diff --git a/cloud2cloud-connector/test/test.go b/cloud2cloud-connector/test/test.go index 94b90604a..398879c7b 100644 --- a/cloud2cloud-connector/test/test.go +++ b/cloud2cloud-connector/test/test.go @@ -51,7 +51,7 @@ func SetUpClouds(ctx context.Context, t *testing.T, deviceID string, supportedEv cloud2 := SetUpCloudWithConnector(t) ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - cloud1Conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + cloud1Conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/cloud2cloud-gateway/service/httpApi.go b/cloud2cloud-gateway/service/httpApi.go index 968f254c0..b8df6758f 100644 --- a/cloud2cloud-gateway/service/httpApi.go +++ b/cloud2cloud-gateway/service/httpApi.go @@ -172,7 +172,7 @@ func NewHTTP(requestHandler *RequestHandler, authInterceptor kitNetHttp.Intercep r := router.NewRouter() r.StrictSlash(true) r.Use(kitNetHttp.CreateLoggingMiddleware(kitNetHttp.WithLogger(logger))) - r.Use(kitNetHttp.CreateAuthMiddleware(authInterceptor, func(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) { + r.Use(kitNetHttp.CreateAuthMiddleware(authInterceptor, func(_ context.Context, w http.ResponseWriter, r *http.Request, err error) { logAndWriteErrorResponse(fmt.Errorf("cannot process request on %v: %w", r.RequestURI, err), http.StatusUnauthorized, w) })) diff --git a/cloud2cloud-gateway/service/retrieveAllDevicesSubscription_test.go b/cloud2cloud-gateway/service/retrieveAllDevicesSubscription_test.go index 455e38a8f..d894edc55 100644 --- a/cloud2cloud-gateway/service/retrieveAllDevicesSubscription_test.go +++ b/cloud2cloud-gateway/service/retrieveAllDevicesSubscription_test.go @@ -32,7 +32,7 @@ func TestRequestHandlerRetrieveDevicesSubscription(t *testing.T) { tearDown := service.SetUp(ctx, t) defer tearDown() - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/cloud2cloud-gateway/service/retrieveDevice.go b/cloud2cloud-gateway/service/retrieveDevice.go index fd972a7e7..36fde2079 100644 --- a/cloud2cloud-gateway/service/retrieveDevice.go +++ b/cloud2cloud-gateway/service/retrieveDevice.go @@ -65,7 +65,7 @@ func (rh *RequestHandler) GetResourceLinks(ctx context.Context, deviceIdFilter [ } } if len(resourceLinks) == 0 { - return nil, fmt.Errorf("cannot get resource links: not found") + return nil, errors.New("cannot get resource links: not found") } return resourceLinks, nil } @@ -91,11 +91,11 @@ func unmarshalContent(c *commands.Content, m interface{}) error { case message.TextPlain.String(): switch v := m.(type) { case *string: - *v = string(c.Data) + *v = string(c.GetData()) case *[]byte: - *v = c.Data + *v = c.GetData() case *interface{}: - *v = string(c.Data) + *v = string(c.GetData()) default: return fmt.Errorf("cannot unmarshal resource content: invalid type (%T)", m) } @@ -216,7 +216,7 @@ func (rh *RequestHandler) RetrieveDeviceWithContentQuery(ctx context.Context, w case ContentQueryAllValue: return rh.RetrieveDeviceWithRepresentations(ctx, w, routeVars[deviceIDKey], encoder) } - return http.StatusBadRequest, fmt.Errorf("invalid content query parameter") + return http.StatusBadRequest, errors.New("invalid content query parameter") } func (rh *RequestHandler) RetrieveDevice(w http.ResponseWriter, r *http.Request) { diff --git a/cloud2cloud-gateway/service/retrieveDeviceSubscription_test.go b/cloud2cloud-gateway/service/retrieveDeviceSubscription_test.go index faa15c1d6..023a3200e 100644 --- a/cloud2cloud-gateway/service/retrieveDeviceSubscription_test.go +++ b/cloud2cloud-gateway/service/retrieveDeviceSubscription_test.go @@ -35,7 +35,7 @@ func TestRequestHandlerRetrieveDeviceSubscription(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/cloud2cloud-gateway/service/retrieveDevice_test.go b/cloud2cloud-gateway/service/retrieveDevice_test.go index 81cea0cbb..b8abebabb 100644 --- a/cloud2cloud-gateway/service/retrieveDevice_test.go +++ b/cloud2cloud-gateway/service/retrieveDevice_test.go @@ -61,12 +61,14 @@ type DevicesAllRepresentation struct { func getDevicesAllRepresentation(t *testing.T, deviceID, deviceName, switchID string) DevicesAllRepresentation { links := test.GetAllBackendResourceRepresentations(t, deviceID, deviceName) for i := range links { + links[i].ResourceTypes = nil if strings.HasSuffix(links[i].Href, test.TestResourceSwitchesHref) { l := test.DefaultSwitchResourceLink(deviceID, switchID) l.DeviceID = "" links[i].Representation = schema.ResourceLinks{l} continue } + // according OCF spec, resource link should not contain resource types field with content } links = append(links, test.ResourceLinkRepresentation{ Href: "/" + commands.NewResourceID(deviceID, test.TestResourceSwitchesInstanceHref(switchID)).ToString(), @@ -92,7 +94,7 @@ func TestRequestHandlerRetrieveDevice(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -268,6 +270,9 @@ func TestRequestHandlerRetrieveDevice(t *testing.T) { d.Device.ProtocolIndependentID = "" d.Device.ManufacturerName = nil d.Links = d.Links.Sort() + for i := range d.Links { + d.Links[i].ResourceTypes = nil + } got = d } else if _, ok := tt.want.(DevicesBaseRepresentation); ok { d := DevicesBaseRepresentation{} diff --git a/cloud2cloud-gateway/service/retrieveResource.go b/cloud2cloud-gateway/service/retrieveResource.go index a9f99d3b9..1dd61b911 100644 --- a/cloud2cloud-gateway/service/retrieveResource.go +++ b/cloud2cloud-gateway/service/retrieveResource.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "net/http" "strings" @@ -48,7 +49,7 @@ func (rh *RequestHandler) RetrieveResourceWithContentQuery(ctx context.Context, } return code, err } - return http.StatusBadRequest, fmt.Errorf("invalid content query parameter") + return http.StatusBadRequest, errors.New("invalid content query parameter") } func (rh *RequestHandler) RetrieveResource(w http.ResponseWriter, r *http.Request) { diff --git a/cloud2cloud-gateway/service/retrieveResourceSubscription.go b/cloud2cloud-gateway/service/retrieveResourceSubscription.go index 738f408bd..b61d7766f 100644 --- a/cloud2cloud-gateway/service/retrieveResourceSubscription.go +++ b/cloud2cloud-gateway/service/retrieveResourceSubscription.go @@ -1,6 +1,7 @@ package service import ( + "errors" "fmt" "net/http" @@ -15,7 +16,7 @@ func (rh *RequestHandler) retrieveSubscription(w http.ResponseWriter, r *http.Re sub, ok := rh.subMgr.Load(subscriptionID) if !ok { - return http.StatusNotFound, fmt.Errorf("not found") + return http.StatusNotFound, errors.New("not found") } if href != "" && sub.Href != href { diff --git a/cloud2cloud-gateway/service/retrieveResourceSubscription_test.go b/cloud2cloud-gateway/service/retrieveResourceSubscription_test.go index 051879cf0..ee53eb16d 100644 --- a/cloud2cloud-gateway/service/retrieveResourceSubscription_test.go +++ b/cloud2cloud-gateway/service/retrieveResourceSubscription_test.go @@ -35,7 +35,7 @@ func TestRequestHandlerRetrieveResourceSubscription(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/cloud2cloud-gateway/service/retrieveResource_test.go b/cloud2cloud-gateway/service/retrieveResource_test.go index ba3868ed4..84ca55784 100644 --- a/cloud2cloud-gateway/service/retrieveResource_test.go +++ b/cloud2cloud-gateway/service/retrieveResource_test.go @@ -34,7 +34,7 @@ func TestRequestHandlerRetrieveResource(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/cloud2cloud-gateway/service/subscribeToDevice_test.go b/cloud2cloud-gateway/service/subscribeToDevice_test.go index 45e4bfd6e..bc920e07b 100644 --- a/cloud2cloud-gateway/service/subscribeToDevice_test.go +++ b/cloud2cloud-gateway/service/subscribeToDevice_test.go @@ -46,7 +46,7 @@ func TestRequestHandlerSubscribeToDevicePublishedOnly(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -66,7 +66,7 @@ func TestRequestHandlerSubscribeToDevicePublishedOnly(t *testing.T) { subID := subscriber.Subscribe(ctx, t, token, deviceID, "", c2cEvents.EventTypes{c2cEvents.EventType_ResourcesPublished}) ev := <-dataChan - publishedResources := test.ResourceLinksToResources(deviceID, test.TestDevsimResources) + publishedResources := test.ResourceLinksToResources(deviceID, test.GetAllBackendResourceLinks()) assert.Equal(t, c2cEvents.EventType_ResourcesPublished, ev.GetHeader().EventType) links := ev.GetData().(schema.ResourceLinks) resources := testSubscribeToDeviceDecodeResources(links) @@ -91,7 +91,7 @@ func TestRequestHandlerSubscribeToDevice(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -118,7 +118,7 @@ func TestRequestHandlerSubscribeToDevice(t *testing.T) { require.Len(t, events, 2) for _, ev := range events { if ev.GetHeader().EventType == c2cEvents.EventType_ResourcesPublished { - publishedResources := test.ResourceLinksToResources(deviceID, test.TestDevsimResources) + publishedResources := test.ResourceLinksToResources(deviceID, test.GetAllBackendResourceLinks()) links := ev.GetData().(schema.ResourceLinks) resources := testSubscribeToDeviceDecodeResources(links) test.CheckProtobufs(t, publishedResources, resources, test.RequireToCheckFunc(require.Equal)) @@ -157,7 +157,7 @@ func TestRequestHandlerSubscribeToDevice(t *testing.T) { resources = testSubscribeToDeviceDecodeResources(links) var unpublishedSwitches []*commands.Resource for _, res := range resources { - if res.Href == test.TestResourceSwitchesInstanceHref(switchID2) { + if res.GetHref() == test.TestResourceSwitchesInstanceHref(switchID2) { unpublishedSwitches = append(unpublishedSwitches, &commands.Resource{ DeviceId: deviceID, Href: test.TestResourceSwitchesInstanceHref(switchID2), diff --git a/cloud2cloud-gateway/service/subscribeToDevices_test.go b/cloud2cloud-gateway/service/subscribeToDevices_test.go index 4b6fed496..c8cef2096 100644 --- a/cloud2cloud-gateway/service/subscribeToDevices_test.go +++ b/cloud2cloud-gateway/service/subscribeToDevices_test.go @@ -54,7 +54,7 @@ func TestRequestHandlerSubscribeToDevices(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -77,21 +77,21 @@ func TestRequestHandlerSubscribeToDevices(t *testing.T) { r := router.NewRouter() r.StrictSlash(true) r.HandleFunc(eventsURI, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - h, err := events.ParseEventHeader(r) - assert.NoError(t, err) + h, err2 := events.ParseEventHeader(r) + assert.NoError(t, err2) //nolint:testifylint defer func() { _ = r.Body.Close() }() assert.Equal(t, wantEventType, h.EventType) - buf, err := io.ReadAll(r.Body) - assert.NoError(t, err) + buf, err2 := io.ReadAll(r.Body) + assert.NoError(t, err2) //nolint:testifylint var v interface{} - err = json.Decode(buf, &v) - assert.NoError(t, err) - assert.Equal(t, v, wantEventContent) + err2 = json.Decode(buf, &v) + assert.NoError(t, err2) //nolint:testifylint + assert.Equal(t, wantEventContent, v) w.WriteHeader(http.StatusOK) - err = eventsServer.Close() - assert.NoError(t, err) + err2 = eventsServer.Close() + assert.NoError(t, err2) })).Methods("POST") _ = http.Serve(eventsServer, r) }() @@ -109,7 +109,7 @@ func TestRequestHandlerSubscribeToDevices(t *testing.T) { require.NoError(t, err) req := testHttp.NewHTTPRequest(http.MethodPost, uri, bytes.NewBuffer(data)).AuthToken(token).Accept(accept).Build(ctx, t) resp := testHttp.DoHTTPRequest(t, req) - assert.Equal(t, wantCode, resp.StatusCode) + require.Equal(t, wantCode, resp.StatusCode) defer func() { _ = resp.Body.Close() }() @@ -147,7 +147,7 @@ func TestRequestHandlerSubscribeToDevicesOffline(t *testing.T) { gwShutdown := coapgwTest.New(t, coapgwCfg) ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -170,21 +170,21 @@ func TestRequestHandlerSubscribeToDevicesOffline(t *testing.T) { r := router.NewRouter() r.StrictSlash(true) r.HandleFunc(eventsURI, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - h, err := events.ParseEventHeader(r) - assert.NoError(t, err) + h, err2 := events.ParseEventHeader(r) + assert.NoError(t, err2) //nolint:testifylint defer func() { _ = r.Body.Close() }() assert.Equal(t, wantEventType, h.EventType) - buf, err := io.ReadAll(r.Body) - assert.NoError(t, err) + buf, err2 := io.ReadAll(r.Body) + assert.NoError(t, err2) //nolint:testifylint var v interface{} - err = json.Decode(buf, &v) - assert.NoError(t, err) - assert.Equal(t, v, wantEventContent) + err2 = json.Decode(buf, &v) + assert.NoError(t, err2) //nolint:testifylint + assert.Equal(t, wantEventContent, v) w.WriteHeader(http.StatusOK) - err = eventsServer.Close() - assert.NoError(t, err) + err2 = eventsServer.Close() + assert.NoError(t, err2) })).Methods("POST") _ = http.Serve(eventsServer, r) }() @@ -202,7 +202,7 @@ func TestRequestHandlerSubscribeToDevicesOffline(t *testing.T) { require.NoError(t, err) req := testHttp.NewHTTPRequest(http.MethodPost, uri, bytes.NewBuffer(data)).AuthToken(oauthTest.GetDefaultAccessToken(t)).Accept(accept).Build(ctx, t) resp := testHttp.DoHTTPRequest(t, req) - assert.Equal(t, wantCode, resp.StatusCode) + require.Equal(t, wantCode, resp.StatusCode) defer func() { _ = resp.Body.Close() }() diff --git a/cloud2cloud-gateway/service/subscribeToResource_test.go b/cloud2cloud-gateway/service/subscribeToResource_test.go index ba1f60bef..b4cf32957 100644 --- a/cloud2cloud-gateway/service/subscribeToResource_test.go +++ b/cloud2cloud-gateway/service/subscribeToResource_test.go @@ -31,7 +31,7 @@ func TestRequestHandlerSubscribeToResource(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -78,7 +78,7 @@ func TestRequestHandlerSubscribeToResourceTokenTimeout(t *testing.T) { defer tearDown() c2cgwShutdown := c2cTest.SetUp(t) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/cloud2cloud-gateway/service/subscriptionManager.go b/cloud2cloud-gateway/service/subscriptionManager.go index eac5d2795..0cd36bac1 100644 --- a/cloud2cloud-gateway/service/subscriptionManager.go +++ b/cloud2cloud-gateway/service/subscriptionManager.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "sync" "time" @@ -73,12 +74,12 @@ func (s *SubscriptionManager) storeToSubs(sub store.Subscription) { func (s *SubscriptionManager) Connect(id string) error { subRaw, ok := s.subscriptions.Load(id) if !ok { - return fmt.Errorf("not found") + return errors.New("not found") } sub := subRaw.(*SubscriptionData) if sub.sub != nil { if !ok { - return fmt.Errorf("already connected") + return errors.New("already connected") } } ctx := s.ctx @@ -108,7 +109,7 @@ func (s *SubscriptionManager) Load(id string) (store.Subscription, bool) { } func cancelSubscription(ctx context.Context, emitEvent emitEventFunc, sub store.Subscription) error { - _, err := emitEvent(ctx, events.EventType_SubscriptionCanceled, sub, func(ctx context.Context) (uint64, error) { + _, err := emitEvent(ctx, events.EventType_SubscriptionCanceled, sub, func(_ context.Context) (uint64, error) { return sub.SequenceNumber, nil }, nil) return err @@ -117,7 +118,7 @@ func cancelSubscription(ctx context.Context, emitEvent emitEventFunc, sub store. func (s *SubscriptionManager) PullOut(ctx context.Context, id, href string) (store.Subscription, error) { subDataRaw, ok := s.subscriptions.PullOut(id) if !ok { - return store.Subscription{}, fmt.Errorf("not found") + return store.Subscription{}, errors.New("not found") } subData := subDataRaw.(*SubscriptionData) if href != "" && subData.data.Href != href { diff --git a/cloud2cloud-gateway/service/subscriptions.go b/cloud2cloud-gateway/service/subscriptions.go index 0d1605a11..80db85b77 100644 --- a/cloud2cloud-gateway/service/subscriptions.go +++ b/cloud2cloud-gateway/service/subscriptions.go @@ -221,7 +221,7 @@ func (s *SubscriptionData) createDevicesSubscription(ctx context.Context, emitEv } for _, e := range eventTypes { - _, err := emitEvent(ctx, e, s.Data(), s.IncrementSequenceNumber, makeDevicesRepresentation([]string{})) + _, err = emitEvent(ctx, e, s.Data(), s.IncrementSequenceNumber, makeDevicesRepresentation([]string{})) if err != nil { return nil, createSubDevicesError(err) } @@ -339,7 +339,7 @@ func (s *SubscriptionData) createDeviceSubscription(ctx context.Context, emitEve func (s *SubscriptionData) Connect(ctx context.Context, emitEvent emitEventFunc, deleteSub func(ctx context.Context, subID, href string) (store.Subscription, error)) error { if s.Subscription() != nil { - return fmt.Errorf("is already connected") + return errors.New("is already connected") } h := closeEventHandler{ ctx: ctx, @@ -361,20 +361,19 @@ func (s *SubscriptionData) Connect(ctx context.Context, emitEvent emitEventFunc, } sub, err := createSubscriptionFunc(ctx, emitEvent, &h) - if err != nil { - if status.Convert(err).Code() == codes.Unauthenticated { - subToCancel, errSub := deleteSub(ctx, s.data.ID, "") - if errSub == nil { - if err2 := cancelSubscription(ctx, emitEvent, subToCancel); err2 != nil { - log.Errorf("cannot cancel subscription %v: %w", subToCancel.ID, err2) - } + if err == nil { + s.Store(sub) + return nil + } + if status.Convert(err).Code() == codes.Unauthenticated { + subToCancel, errSub := deleteSub(ctx, s.data.ID, "") + if errSub == nil { + if err2 := cancelSubscription(ctx, emitEvent, subToCancel); err2 != nil { + log.Errorf("cannot cancel subscription %v: %w", subToCancel.ID, err2) } } - return err } - - s.Store(sub) - return nil + return err } func (s *SubscriptionData) IncrementSequenceNumber(ctx context.Context) (uint64, error) { diff --git a/cloud2cloud-gateway/service/updateResource.go b/cloud2cloud-gateway/service/updateResource.go index 9e4703487..60cb21109 100644 --- a/cloud2cloud-gateway/service/updateResource.go +++ b/cloud2cloud-gateway/service/updateResource.go @@ -47,7 +47,7 @@ func statusToHttpStatus(status commands.Status) int { func sendResponse(w http.ResponseWriter, processed *raEvents.ResourceUpdated) (int, error) { statusCode := statusToHttpStatus(processed.GetStatus()) - if processed.Content != nil { + if processed.GetContent() != nil { var content interface{} err := unmarshalContent(processed.GetContent(), &content) if err != nil { diff --git a/cloud2cloud-gateway/store/mongodb/store.go b/cloud2cloud-gateway/store/mongodb/store.go index 6628c2429..f7b80bf01 100644 --- a/cloud2cloud-gateway/store/mongodb/store.go +++ b/cloud2cloud-gateway/store/mongodb/store.go @@ -3,6 +3,7 @@ package mongodb import ( "context" "crypto/tls" + "errors" "fmt" pkgMongo "github.com/plgd-dev/hub/v2/pkg/mongodb" @@ -22,15 +23,15 @@ func NewStore(ctx context.Context, cfg pkgMongo.Config, tls *tls.Config, tracerP if err != nil { return nil, err } - s.SetOnClear(func(c context.Context) error { - return s.DropCollection(ctx, subscriptionsCName) + s.SetOnClear(func(clearCtx context.Context) error { + return s.DropCollection(clearCtx, subscriptionsCName) }) return &Store{s}, nil } func incrementSubscriptionSequenceNumber(ctx context.Context, col *mongo.Collection, subscriptionID string) (uint64, error) { if subscriptionID == "" { - return 0, fmt.Errorf("cannot increment sequence number: invalid subscriptionID") + return 0, errors.New("cannot increment sequence number: invalid subscriptionID") } var res bson.M diff --git a/cloud2cloud-gateway/store/mongodb/subscription.go b/cloud2cloud-gateway/store/mongodb/subscription.go index 2d8513960..8649063ca 100644 --- a/cloud2cloud-gateway/store/mongodb/subscription.go +++ b/cloud2cloud-gateway/store/mongodb/subscription.go @@ -75,49 +75,49 @@ func makeDBSub(sub store.Subscription) DBSub { func validateDevicesSubscription(sub store.Subscription) error { if sub.DeviceID != "" { - return fmt.Errorf("invalid DeviceID for devices subscription type") + return errors.New("invalid DeviceID for devices subscription type") } if sub.Href != "" { - return fmt.Errorf("invalid Href for devices subscription type") + return errors.New("invalid Href for devices subscription type") } return nil } func validateDeviceSubscription(sub store.Subscription) error { if sub.DeviceID == "" { - return fmt.Errorf("invalid DeviceID for device subscription type") + return errors.New("invalid DeviceID for device subscription type") } if sub.Href != "" { - return fmt.Errorf("invalid Href for device subscription type") + return errors.New("invalid Href for device subscription type") } return nil } func validateResourceSubscription(sub store.Subscription) error { if sub.DeviceID == "" { - return fmt.Errorf("invalid DeviceID for resource subscription type") + return errors.New("invalid DeviceID for resource subscription type") } if sub.Href == "" { - return fmt.Errorf("invalid Href for resource subscription type") + return errors.New("invalid Href for resource subscription type") } return nil } func validateSubscription(sub store.Subscription) error { if sub.ID == "" { - return fmt.Errorf("invalid ID") + return errors.New("invalid ID") } if len(sub.EventTypes) == 0 { - return fmt.Errorf("invalid EventTypes") + return errors.New("invalid EventTypes") } if sub.URL == "" { - return fmt.Errorf("invalid URL") + return errors.New("invalid URL") } if sub.SigningSecret == "" { - return fmt.Errorf("invalid SigningSecret") + return errors.New("invalid SigningSecret") } if sub.AccessToken == "" { - return fmt.Errorf("invalid AccessToken") + return errors.New("invalid AccessToken") } switch sub.Type { @@ -156,7 +156,7 @@ func (s *Store) IncrementSubscriptionSequenceNumber(ctx context.Context, subscri func (s *Store) SetInitialized(ctx context.Context, subscriptionID string) error { col := s.Collection(subscriptionsCName) if subscriptionID == "" { - return fmt.Errorf("cannot set initialized: invalid subscriptionId") + return errors.New("cannot set initialized: invalid subscriptionId") } opts := &options.UpdateOptions{} @@ -193,7 +193,7 @@ func (s *Store) LoadSubscriptions(ctx context.Context, query store.SubscriptionQ case query.Type == "" && query.DeviceID == "" && query.Href == "": iter, err = col.Find(ctx, bson.M{}) case query.Type == "": - return fmt.Errorf("invalid Type") + return errors.New("invalid Type") case query.DeviceID != "" && query.Href != "": q := bson.M{ typeKey: query.Type, diff --git a/cloud2cloud-gateway/test/events.go b/cloud2cloud-gateway/test/events.go index c59398a91..aad72ac83 100644 --- a/cloud2cloud-gateway/test/events.go +++ b/cloud2cloud-gateway/test/events.go @@ -57,25 +57,29 @@ func WaitForEvents(ch EventChan, timeout time.Duration) []Event { return events } -func DecodeEvent(t *testing.T, etype events.EventType, data []byte) interface{} { +func decodeEvent(etype events.EventType, data []byte) (interface{}, error) { switch etype { case events.EventType_ResourcesPublished: fallthrough case events.EventType_ResourcesUnpublished: var links schema.ResourceLinks err := json.Decode(data, &links) - assert.NoError(t, err) - return links + if err != nil { + return nil, err + } + return links, nil case events.EventType_ResourceChanged: var colContent []map[interface{}]interface{} err := json.Decode(data, &colContent) if err == nil { - return colContent + return colContent, nil } var content map[interface{}]interface{} err = json.Decode(data, &content) - assert.NoError(t, err) - return content + if err != nil { + return nil, err + } + return content, nil case events.EventType_DevicesRegistered: fallthrough case events.EventType_DevicesUnregistered: @@ -85,11 +89,13 @@ func DecodeEvent(t *testing.T, etype events.EventType, data []byte) interface{} case events.EventType_DevicesOffline: var devices []map[string]string err := json.Decode(data, &devices) - assert.NoError(t, err) - return devices + if err != nil { + return nil, err + } + return devices, nil } - return nil + return nil, nil } func NewEventsServer(t *testing.T, uri string) *EventsServer { @@ -134,14 +140,15 @@ func (s *EventsServer) Run(t *testing.T) EventChan { r.StrictSlash(true) r.HandleFunc(s.uri, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { h, err := events.ParseEventHeader(r) - assert.NoError(t, err) + assert.NoError(t, err) //nolint:testifylint defer func() { _ = r.Body.Close() }() buf, err := io.ReadAll(r.Body) - assert.NoError(t, err) + assert.NoError(t, err) //nolint:testifylint - data := DecodeEvent(t, h.EventType, buf) + data, err := decodeEvent(h.EventType, buf) + assert.NoError(t, err) //nolint:testifylint dataChan <- Event{ header: h, data: data, diff --git a/coap-gateway/coapconv/coapconv.go b/coap-gateway/coapconv/coapconv.go index a00296795..7ff762d5c 100644 --- a/coap-gateway/coapconv/coapconv.go +++ b/coap-gateway/coapconv/coapconv.go @@ -9,6 +9,8 @@ import ( "strings" "github.com/google/uuid" + "github.com/plgd-dev/device/v2/pkg/codec/cbor" + "github.com/plgd-dev/device/v2/pkg/codec/json" "github.com/plgd-dev/device/v2/schema/interfaces" "github.com/plgd-dev/device/v2/schema/resources" "github.com/plgd-dev/go-coap/v3/message" @@ -18,7 +20,6 @@ import ( "github.com/plgd-dev/hub/v2/coap-gateway/uri" "github.com/plgd-dev/hub/v2/resource-aggregate/commands" "github.com/plgd-dev/hub/v2/resource-aggregate/events" - "github.com/plgd-dev/kit/v2/codec/cbor" ) func StatusToCoapCode(status commands.Status, operation Operation) codes.Code { @@ -110,7 +111,7 @@ func newCoapResourceCreateOrUpdateRequest(ctx context.Context, messagePool *pool return nil, fmt.Errorf("invalid content type for request: %w", err) } if content == nil { - return nil, fmt.Errorf("invalid content for request") + return nil, errors.New("invalid content for request") } token, err := message.GetToken() if err != nil { @@ -310,14 +311,20 @@ func NewConfirmResourceDeleteRequest(resourceID *commands.ResourceId, correlatio } } -func NewNotifyResourceChangedRequest(resourceID *commands.ResourceId, connectionID string, req *pool.Message) *commands.NotifyResourceChangedRequest { +func NewNotifyResourceChangedRequest(resourceID *commands.ResourceId, resourceTypes []string, connectionID string, req *pool.Message) *commands.NotifyResourceChangedRequest { content := NewContent(req.Options(), req.Body()) metadata := NewCommandMetadata(req.Sequence(), connectionID) + rtFromBody := tryToGetResourceTypesFromContent(content.GetCoapContentFormat(), content.GetData()) + if len(rtFromBody) > 0 { + resourceTypes = rtFromBody + } + return &commands.NotifyResourceChangedRequest{ ResourceId: resourceID, Content: content, CommandMetadata: metadata, + ResourceTypes: resourceTypes, Status: CoapCodeToStatus(req.Code(), Update), Etag: getETagFromMessage(req), } @@ -344,6 +351,30 @@ func filterOutEmptyResource(resource resources.BatchRepresentation) (isEmpty boo return isEmpty, false } +type ct struct { + ResourceTypes []string `json:"rt"` +} + +func tryToGetResourceTypesFromContent(contentFormat int32, content []byte) []string { + if len(content) == 0 { + return nil + } + decode := func([]byte, interface{}) error { + return errors.New("unsupported") + } + switch contentFormat { + case int32(message.AppOcfCbor), int32(message.AppCBOR): + decode = cbor.Decode + case int32(message.AppJSON): + decode = json.Decode + } + var c ct + if err := decode(content, &c); err == nil { + return c.ResourceTypes + } + return nil +} + func NewNotifyResourceChangedRequestsFromBatchResourceDiscovery(deviceID, connectionID string, req *pool.Message) ([]*commands.NotifyResourceChangedRequest, error) { data, contentFormat := GetContentData(req.Options(), req.Body()) metadata := NewCommandMetadata(req.Sequence(), connectionID) @@ -378,6 +409,10 @@ func NewNotifyResourceChangedRequestsFromBatchResourceDiscovery(deviceID, connec data = nil code = commands.Status_NOT_FOUND } + resourceTypes := r.ResourceTypes + if len(resourceTypes) == 0 { + resourceTypes = tryToGetResourceTypesFromContent(contentFormat, r.Content) + } resourceChangedReq := &commands.NotifyResourceChangedRequest{ ResourceId: commands.NewResourceID(deviceID, r.Href()), Content: &commands.Content{ @@ -388,6 +423,7 @@ func NewNotifyResourceChangedRequestsFromBatchResourceDiscovery(deviceID, connec CommandMetadata: metadata, Status: code, Etag: r.ETag, + ResourceTypes: resourceTypes, } if len(etag) > 0 && bytes.Equal(etag, r.ETag) { latestETagResource = resourceChangedReq @@ -416,8 +452,8 @@ func NewUpdateResourceRequest(resourceID *commands.ResourceId, req *mux.Message, return &commands.UpdateResourceRequest{ ResourceId: resourceID, Content: &commands.Content{ - Data: content.Data, - ContentType: content.ContentType, + Data: content.GetData(), + ContentType: content.GetContentType(), }, ResourceInterface: resourceInterface, CommandMetadata: metadata, diff --git a/coap-gateway/service/auth.go b/coap-gateway/service/auth.go index 407beea6e..72003e5b5 100644 --- a/coap-gateway/service/auth.go +++ b/coap-gateway/service/auth.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "crypto/x509" + "errors" "fmt" "time" @@ -20,14 +21,14 @@ import ( type Interceptor = func(ctx context.Context, code codes.Code, path string) (context.Context, error) func newAuthInterceptor() Interceptor { - return func(ctx context.Context, code codes.Code, path string) (context.Context, error) { + return func(ctx context.Context, _ codes.Code, path string) (context.Context, error) { switch path { case uri.RefreshToken, uri.SignUp, uri.SignIn, plgdtime.ResourceURI: return ctx, nil } e := ctx.Value(&authCtxKey) if e == nil { - return ctx, fmt.Errorf("invalid authorization context") + return ctx, errors.New("invalid authorization context") } authCtx := e.(*authorizationContext) err := authCtx.IsValid() @@ -60,7 +61,7 @@ func (s *Service) verifyDeviceID(tlsDeviceID string, claim pkgJwt.Claims) (strin return jwtDeviceID, nil } if tlsDeviceID == "" { - return "", fmt.Errorf("certificate of device doesn't contain device id") + return "", errors.New("certificate of device doesn't contain device id") } if s.config.APIs.COAP.Authorization.DeviceIDClaim != "" && jwtDeviceID != tlsDeviceID { return "", fmt.Errorf("access token issued to the device ('%v') used by the different device ('%v')", jwtDeviceID, tlsDeviceID) @@ -81,7 +82,7 @@ func (s *Service) VerifyAndResolveDeviceID(tlsDeviceID, paramDeviceID string, cl func verifyChain(chain []*x509.Certificate, capool *x509.CertPool, identityPropertiesRequired bool) error { if len(chain) == 0 { - return fmt.Errorf("certificate chain is empty") + return errors.New("certificate chain is empty") } certificate := chain[0] intermediateCAPool := x509.NewCertPool() @@ -109,10 +110,10 @@ func verifyChain(chain []*x509.Certificate, capool *x509.CertPool, identityPrope } } if !ekuHasClient { - return fmt.Errorf("the extended key usage field in the device certificate does not contain client authentication") + return errors.New("the extended key usage field in the device certificate does not contain client authentication") } if !ekuHasServer { - return fmt.Errorf("the extended key usage field in the device certificate does not contain server authentication") + return errors.New("the extended key usage field in the device certificate does not contain server authentication") } if !identityPropertiesRequired { return nil @@ -130,18 +131,18 @@ func MakeGetConfigForClient(tlsCfg *tls.Config, identityPropertiesRequired bool) MinVersion: tlsCfg.MinVersion, ClientAuth: tlsCfg.ClientAuth, ClientCAs: tlsCfg.ClientCAs, - VerifyPeerCertificate: func(rawCerts [][]byte, chains [][]*x509.Certificate) error { - var errors *multierror.Error + VerifyPeerCertificate: func(_ [][]byte, chains [][]*x509.Certificate) error { + var errs *multierror.Error for _, chain := range chains { err := verifyChain(chain, tlsCfg.ClientCAs, identityPropertiesRequired) if err == nil { return nil } - errors = multierror.Append(errors, err) + errs = multierror.Append(errs, err) } - err := fmt.Errorf("empty chains") - if errors.ErrorOrNil() != nil { - err = errors + err := errors.New("empty chains") + if errs.ErrorOrNil() != nil { + err = errs } return pkgX509.NewError(chains, err) }, diff --git a/coap-gateway/service/clientCreateHandler.go b/coap-gateway/service/clientCreateHandler.go index b61c21d28..1cd264066 100644 --- a/coap-gateway/service/clientCreateHandler.go +++ b/coap-gateway/service/clientCreateHandler.go @@ -37,14 +37,14 @@ func clientCreateHandler(req *mux.Message, client *session) (*pool.Message, erro code = coapconv.GrpcErr2CoapCode(err, coapconv.Create) return nil, statusErrorf(code, errFmtCreateResource, fmt.Sprintf(" /%v%v", deviceID, href), err) } - if content == nil || len(content.Data) == 0 { + if len(content.GetData()) == 0 { return client.createResponse(code, req.Token(), coapMessage.TextPlain, nil), nil } - mediaType, err := coapconv.MakeMediaType(-1, content.ContentType) + mediaType, err := coapconv.MakeMediaType(-1, content.GetContentType()) if err != nil { return nil, statusErrorf(coapCodes.BadRequest, "cannot encode response for create resource %v: %w", fmt.Sprintf(" /%v%v", deviceID, href), err) } - return client.createResponse(code, req.Token(), mediaType, content.Data), nil + return client.createResponse(code, req.Token(), mediaType, content.GetData()), nil } func clientCreateDeviceHandler(req *mux.Message, client *session, deviceID, href string) (*commands.Content, error) { diff --git a/coap-gateway/service/clientDeleteHandler.go b/coap-gateway/service/clientDeleteHandler.go index 1f346c765..cc5ed7488 100644 --- a/coap-gateway/service/clientDeleteHandler.go +++ b/coap-gateway/service/clientDeleteHandler.go @@ -38,14 +38,14 @@ func clientDeleteHandler(req *mux.Message, client *session) (*pool.Message, erro return nil, statusErrorf(code, errFmtDeleteResource, fmt.Sprintf(" /%v%v", deviceID, href), err) } - if content == nil || len(content.Data) == 0 { + if len(content.GetData()) == 0 { return client.createResponse(code, req.Token(), coapMessage.TextPlain, nil), nil } - mediaType, err := coapconv.MakeMediaType(-1, content.ContentType) + mediaType, err := coapconv.MakeMediaType(-1, content.GetContentType()) if err != nil { return nil, statusErrorf(code, errFmtDeleteResource, fmt.Sprintf(" /%v%v", deviceID, href), err) } - return client.createResponse(code, req.Token(), mediaType, content.Data), nil + return client.createResponse(code, req.Token(), mediaType, content.GetData()), nil } func clientDeleteResourceHandler(req *mux.Message, client *session, deviceID, href string) (*commands.Content, error) { diff --git a/coap-gateway/service/clientObserveHandler.go b/coap-gateway/service/clientObserveHandler.go index 2221886d5..00f8d4813 100644 --- a/coap-gateway/service/clientObserveHandler.go +++ b/coap-gateway/service/clientObserveHandler.go @@ -178,17 +178,14 @@ func (s *resourceSubscription) Init(ctx context.Context) error { var d *events.ResourceChanged for { - resource, err := client.Recv() - if errors.Is(err, io.EOF) { + resource, errR := client.Recv() + if errors.Is(errR, io.EOF) { break } - if err != nil { - return err + if errR != nil { + return errR } - d = resource.Data - } - if err != nil { - return err + d = resource.GetData() } authCtx, err := s.client.GetAuthorizationContext() if err != nil { @@ -254,7 +251,7 @@ func startResourceObservation(req *mux.Message, client *session, authCtx *author return nil, statusErrorf(coapconv.GrpcErr2CoapCode(err, coapconv.Retrieve), "%w", getStartObserveResourceErr(deviceID, href, err)) } if !ok { - return nil, statusErrorf(coapCodes.Unauthorized, "%w", getStartObserveResourceErr(deviceID, href, fmt.Errorf("unauthorized access"))) + return nil, statusErrorf(coapCodes.Unauthorized, "%w", getStartObserveResourceErr(deviceID, href, errors.New("unauthorized access"))) } token := req.Token().String() sub := newResourceSubscription(req, client, authCtx, deviceID, href) @@ -294,7 +291,7 @@ func stopResourceObservation(req *mux.Message, client *session, deviceID, href s return nil, statusErrorf(coapCodes.BadRequest, "%w", getStopObserveResourceErr(deviceID, href, err)) } if !canceled { - return nil, statusErrorf(coapCodes.BadRequest, "%w", getStopObserveResourceErr(deviceID, href, fmt.Errorf("subscription not found"))) + return nil, statusErrorf(coapCodes.BadRequest, "%w", getStopObserveResourceErr(deviceID, href, errors.New("subscription not found"))) } return CreateResourceContentToObserver(client, nil, 1, req.Token()) } @@ -306,7 +303,7 @@ func clientResetObservationHandler(req *mux.Message, client *session) (*pool.Mes return nil, statusErrorf(coapCodes.BadRequest, "%w", fmt.Errorf("cannot reset resource observation: %w", err)) } if !canceled { - return nil, statusErrorf(coapCodes.BadRequest, "%w", fmt.Errorf("cannot reset resource observation: not found")) + return nil, statusErrorf(coapCodes.BadRequest, "%w", errors.New("cannot reset resource observation: not found")) } // reset does not send response return nil, nil diff --git a/coap-gateway/service/clientObserveHandler_test.go b/coap-gateway/service/clientObserveHandler_test.go index aa8fa146d..1c67158fe 100644 --- a/coap-gateway/service/clientObserveHandler_test.go +++ b/coap-gateway/service/clientObserveHandler_test.go @@ -145,7 +145,7 @@ func TestClientObserveHandlerCloseObservation(t *testing.T) { require.NoError(t, err) ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/coap-gateway/service/clientObserver.go b/coap-gateway/service/clientObserver.go index 07df6b2d9..61a141d9a 100644 --- a/coap-gateway/service/clientObserver.go +++ b/coap-gateway/service/clientObserver.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "github.com/plgd-dev/hub/v2/coap-gateway/service/observation" @@ -30,7 +31,7 @@ func (c *session) getDeviceObserver(ctx context.Context) (*observation.DeviceObs } deviceObserver, ok := v.(*observation.DeviceObserver) if !ok { - return nil, false, getError(fmt.Errorf("invalid future value")) + return nil, false, getError(errors.New("invalid future value")) } return deviceObserver, true, nil } @@ -59,8 +60,7 @@ func (c *session) replaceDeviceObserverWithDeviceTwin(ctx context.Context, twinE observationType = obs.GetObservationType() } if deviceID == "" { - err := fmt.Errorf("cannot replace device observer: invalid device id") - return false, err + return false, errors.New("cannot replace device observer: invalid device id") } twinEnabled = twinEnabled || twinForceSynchronization if !twinForceSynchronization && prevTwinEnabled == twinEnabled { @@ -68,8 +68,8 @@ func (c *session) replaceDeviceObserverWithDeviceTwin(ctx context.Context, twinE } deviceObserverFuture, setDeviceObserver := future.New() oldDeviceObserver := c.replaceDeviceObserver(deviceObserverFuture) - if err := cleanDeviceObserver(ctx, oldDeviceObserver); err != nil { - c.Errorf("failed to close replaced device observer: %w", err) + if errD := cleanDeviceObserver(ctx, oldDeviceObserver); errD != nil { + c.Errorf("failed to close replaced device observer: %w", errD) } deviceObserver, err := observation.NewDeviceObserver(c.Context(), deviceID, c, c, c, @@ -98,7 +98,7 @@ func toDeviceObserver(ctx context.Context, devObsFut *future.Future) (*observati } deviceObserver, ok := v.(*observation.DeviceObserver) if !ok { - return nil, fmt.Errorf("invalid future value") + return nil, errors.New("invalid future value") } return deviceObserver, nil } diff --git a/coap-gateway/service/clientRetrieveHandler.go b/coap-gateway/service/clientRetrieveHandler.go index 99b72f21a..c00f265e0 100644 --- a/coap-gateway/service/clientRetrieveHandler.go +++ b/coap-gateway/service/clientRetrieveHandler.go @@ -57,14 +57,14 @@ func clientRetrieveHandler(req *mux.Message, client *session) (*pool.Message, er } } - if content == nil || len(content.Data) == 0 { + if len(content.GetData()) == 0 { return client.createResponse(code, req.Token(), coapMessage.TextPlain, nil), nil } - mediaType, err := coapconv.MakeMediaType(-1, content.ContentType) + mediaType, err := coapconv.MakeMediaType(-1, content.GetContentType()) if err != nil { return nil, statusErrorf(code, errFmtRetrieveResource, fmt.Sprintf(" /%v%v", deviceID, href), err) } - return client.createResponse(code, req.Token(), mediaType, content.Data), nil + return client.createResponse(code, req.Token(), mediaType, content.GetData()), nil } func clientRetrieveFromResourceTwinHandler(ctx context.Context, client *session, deviceID, href string, etag []byte) (*commands.Content, coapCodes.Code, error) { @@ -91,14 +91,14 @@ func clientRetrieveFromResourceTwinHandler(ctx context.Context, client *session, if err != nil { return nil, coapconv.GrpcErr2CoapCode(err, coapconv.Retrieve), err } - if resourceValue.GetData().GetResourceId().GetDeviceId() == deviceID && resourceValue.GetData().GetResourceId().GetHref() == href && resourceValue.GetData().Content != nil { + if resourceValue.GetData().GetResourceId().GetDeviceId() == deviceID && resourceValue.GetData().GetResourceId().GetHref() == href && resourceValue.GetData().GetContent() != nil { if etag != nil && bytes.Equal(etag, resourceValue.GetData().GetEtag()) { return nil, coapCodes.Valid, nil } - return resourceValue.GetData().Content, coapCodes.Content, nil + return resourceValue.GetData().GetContent(), coapCodes.Content, nil } } - return nil, coapCodes.NotFound, fmt.Errorf("not found") + return nil, coapCodes.NotFound, errors.New("not found") } func clientRetrieveFromDeviceHandler(req *mux.Message, client *session, deviceID, href string) (*commands.Content, coapCodes.Code, error) { diff --git a/coap-gateway/service/clientRetrieveHandler_test.go b/coap-gateway/service/clientRetrieveHandler_test.go index 1484fed73..150d85fae 100644 --- a/coap-gateway/service/clientRetrieveHandler_test.go +++ b/coap-gateway/service/clientRetrieveHandler_test.go @@ -106,7 +106,7 @@ func TestClientRetrieveHandler(t *testing.T) { req.SetOptionString(message.URIQuery, tt.args.query) } resp, err := co.Do(req) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, tt.wantsCode.String(), resp.Code().String()) }) } diff --git a/coap-gateway/service/clientUpdateHandler.go b/coap-gateway/service/clientUpdateHandler.go index 4d76f09db..c3b6564ba 100644 --- a/coap-gateway/service/clientUpdateHandler.go +++ b/coap-gateway/service/clientUpdateHandler.go @@ -47,14 +47,14 @@ func clientUpdateHandler(req *mux.Message, client *session) (*pool.Message, erro code = coapconv.GrpcErr2CoapCode(err, coapconv.Update) return nil, statusErrorf(code, errFmtUpdateResource, fmt.Sprintf(" /%v%v", deviceID, href), err) } - if content == nil || len(content.Data) == 0 { + if len(content.GetData()) == 0 { return client.createResponse(code, req.Token(), coapMessage.TextPlain, nil), nil } - mediaType, err := coapconv.MakeMediaType(-1, content.ContentType) + mediaType, err := coapconv.MakeMediaType(-1, content.GetContentType()) if err != nil { return nil, statusErrorf(code, "cannot encode response for update resource /%v%v: %w", deviceID, href, err) } - return client.createResponse(code, req.Token(), mediaType, content.Data), nil + return client.createResponse(code, req.Token(), mediaType, content.GetData()), nil } func clientUpdateDeviceHandler(req *mux.Message, client *session, deviceID, href string) (*commands.Content, error) { diff --git a/coap-gateway/service/config.go b/coap-gateway/service/config.go index e49aa1e61..2f488fa65 100644 --- a/coap-gateway/service/config.go +++ b/coap-gateway/service/config.go @@ -1,6 +1,7 @@ package service import ( + "errors" "fmt" "time" @@ -174,7 +175,7 @@ func (c *COAPConfigMarshalerUnmarshaler) Validate() error { return err } if !c.InjectedCOAPConfig.TLSConfig.IdentityPropertiesRequired && c.Authorization.DeviceIDClaim != "" { - return fmt.Errorf("tls.identityPropertiesRequired('%v') - %w", c.InjectedCOAPConfig.TLSConfig.IdentityPropertiesRequired, fmt.Errorf("combination with authorization.deviceIDClaim is not supported")) + return fmt.Errorf("tls.identityPropertiesRequired('%v') - %w", c.InjectedCOAPConfig.TLSConfig.IdentityPropertiesRequired, errors.New("combination with authorization.deviceIDClaim is not supported")) } return nil } diff --git a/coap-gateway/service/devicesStatusUpdater.go b/coap-gateway/service/devicesStatusUpdater.go index 6077ab19f..e5f1875ce 100644 --- a/coap-gateway/service/devicesStatusUpdater.go +++ b/coap-gateway/service/devicesStatusUpdater.go @@ -40,10 +40,11 @@ func (u *devicesStatusUpdater) updateOnlineStatus(ctx context.Context, client *s DeviceId: authCtx.GetDeviceID(), Update: &commands.UpdateDeviceMetadataRequest_Connection{ Connection: &commands.Connection{ - Status: commands.Connection_ONLINE, - ConnectedAt: pkgTime.UnixNano(connectedAt), - Protocol: client.GetApplicationProtocol(), - ServiceId: u.serviceInstanceID.String(), + Status: commands.Connection_ONLINE, + ConnectedAt: pkgTime.UnixNano(connectedAt), + Protocol: client.GetApplicationProtocol(), + ServiceId: u.serviceInstanceID.String(), + LocalEndpoints: client.getLocalEndpoints(), }, }, CommandMetadata: &commands.CommandMetadata{ diff --git a/coap-gateway/service/devicesStatusUpdater_test.go b/coap-gateway/service/devicesStatusUpdater_test.go index 4948dcc90..02eba2127 100644 --- a/coap-gateway/service/devicesStatusUpdater_test.go +++ b/coap-gateway/service/devicesStatusUpdater_test.go @@ -1,5 +1,5 @@ -//go:build test -// +build test +//go:build test || device_integration +// +build test device_integration package service_test @@ -18,21 +18,22 @@ import ( "github.com/plgd-dev/hub/v2/resource-aggregate/commands" test "github.com/plgd-dev/hub/v2/test" "github.com/plgd-dev/hub/v2/test/config" + "github.com/plgd-dev/hub/v2/test/device" oauthService "github.com/plgd-dev/hub/v2/test/oauth-server/service" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" - "github.com/plgd-dev/hub/v2/test/service" + testService "github.com/plgd-dev/hub/v2/test/service" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) -func onboardDeviceAndGetDevice(ctx context.Context, t *testing.T, deviceID string, oauthCfg oauthService.Config, coapCfg coapService.Config) (*pb.Device, time.Time /*startOnboard*/, time.Duration /*delta*/) { - tearDown := service.SetUp(ctx, t, service.WithOAuthConfig(oauthCfg), service.WithCOAPGWConfig(coapCfg)) - defer tearDown() +func onboardDeviceAndGetDevice(ctx context.Context, t *testing.T, device device.Device, oauthCfg oauthService.Config, coapCfg coapService.Config, wait time.Duration) (*pb.Device, time.Time /*startOnboard*/, time.Duration /*delta*/) { + oauthShutdown := oauthTest.New(t, oauthCfg) + servicesTeardown := testService.SetUpServices(context.Background(), t, testService.SetUpServicesCertificateAuthority|testService.SetUpServicesId|testService.SetUpServicesResourceAggregate|testService.SetUpServicesResourceDirectory|testService.SetUpServicesCoapGateway|testService.SetUpServicesGrpcGateway, testService.WithCOAPGWConfig(coapCfg)) ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -42,12 +43,17 @@ func onboardDeviceAndGetDevice(ctx context.Context, t *testing.T, deviceID strin c := pb.NewGrpcGatewayClient(conn) startOnboard := time.Now() - _, shutdownDevSim := test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) - defer shutdownDevSim() + shutdownDevSim := test.OnboardDevice(ctx, t, c, device, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, device.GetDefaultResources()) deltaOnboard := time.Since(startOnboard) / 2 + // stop oauth server to don't allow refresh token during sleep + oauthShutdown() + // for update resource-directory cache - time.Sleep(time.Second) + time.Sleep(wait) + oauthShutdown = oauthTest.New(t, oauthCfg) + ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) + defer oauthShutdown() client, err := c.GetDevices(ctx, &pb.GetDevicesRequest{}) require.NoError(t, err) @@ -58,16 +64,18 @@ func onboardDeviceAndGetDevice(ctx context.Context, t *testing.T, deviceID strin break } require.NoError(t, err) - assert.NotEmpty(t, dev.ProtocolIndependentId) + assert.NotEmpty(t, dev.GetProtocolIndependentId()) dev.ProtocolIndependentId = "" devices = append(devices, dev) } require.Len(t, devices, 1) + shutdownDevSim() + servicesTeardown() return devices[0], startOnboard, deltaOnboard } -func TestDevicesStatusUpdaterDisabledAndDeviceAccessTokenHasNoExpiration(t *testing.T) { - deviceID := test.MustFindDeviceByName(test.TestDeviceName) +func TestDevicesStatusAccessTokenHasNoExpiration(t *testing.T) { + d := test.MustFindTestDevice() ctx, cancel := context.WithTimeout(context.Background(), config.TEST_TIMEOUT) defer cancel() @@ -75,13 +83,13 @@ func TestDevicesStatusUpdaterDisabledAndDeviceAccessTokenHasNoExpiration(t *test oauthCfg.OAuthSigner.Clients.Find(config.OAUTH_MANAGER_CLIENT_ID).AccessTokenLifetime = 0 coapCfg := coapgwTest.MakeConfig(t) - device, _, _ := onboardDeviceAndGetDevice(ctx, t, deviceID, oauthCfg, coapCfg) + device, _, _ := onboardDeviceAndGetDevice(ctx, t, d, oauthCfg, coapCfg, time.Second) assert.Equal(t, commands.Connection_ONLINE, device.Metadata.Connection.Status) } -func TestDevicesStatusUpdaterDisabledAndDeviceAccessTokenHasExpiration(t *testing.T) { - deviceID := test.MustFindDeviceByName(test.TestDeviceName) +func TestDevicesStatusAccessTokenHasExpiration(t *testing.T) { + d := test.MustFindTestDevice() ctx, cancel := context.WithTimeout(context.Background(), config.TEST_TIMEOUT) defer cancel() @@ -89,8 +97,25 @@ func TestDevicesStatusUpdaterDisabledAndDeviceAccessTokenHasExpiration(t *testin accessTokenLifetime := time.Second * 10 oauthCfg.OAuthSigner.Clients.Find(config.OAUTH_MANAGER_CLIENT_ID).AccessTokenLifetime = accessTokenLifetime coapCfg := coapgwTest.MakeConfig(t) + coapCfg.APIs.COAP.OwnerCacheExpiration = time.Second - device, _, _ := onboardDeviceAndGetDevice(ctx, t, deviceID, oauthCfg, coapCfg) + device, _, _ := onboardDeviceAndGetDevice(ctx, t, d, oauthCfg, coapCfg, time.Second) assert.Equal(t, commands.Connection_ONLINE, device.Metadata.Connection.Status) } + +func TestDevicesStatusAccessTokenHasExpirationAndTokenWillExpire(t *testing.T) { + d := test.MustFindTestDevice() + ctx, cancel := context.WithTimeout(context.Background(), config.TEST_TIMEOUT) + defer cancel() + + oauthCfg := oauthTest.MakeConfig(t) + accessTokenLifetime := time.Second * 10 + oauthCfg.OAuthSigner.Clients.Find(config.OAUTH_MANAGER_CLIENT_ID).AccessTokenLifetime = accessTokenLifetime + coapCfg := coapgwTest.MakeConfig(t) + coapCfg.APIs.COAP.OwnerCacheExpiration = time.Second + + device, _, _ := onboardDeviceAndGetDevice(ctx, t, d, oauthCfg, coapCfg, accessTokenLifetime) + + assert.Equal(t, commands.Connection_OFFLINE, device.Metadata.Connection.Status) +} diff --git a/coap-gateway/service/exchangeCache.go b/coap-gateway/service/exchangeCache.go index d0d758e39..b798d44b8 100644 --- a/coap-gateway/service/exchangeCache.go +++ b/coap-gateway/service/exchangeCache.go @@ -2,7 +2,7 @@ package service import ( "context" - "fmt" + "errors" "sync" "github.com/plgd-dev/hub/v2/pkg/security/oauth2" @@ -40,7 +40,7 @@ func (e *ExchangeCache) getFutureToken(authorizationCode string) (*future.Future // Execute Exchange or returned cached value. func (e *ExchangeCache) Execute(ctx context.Context, provider *oauth2.PlgdProvider, authorizationCode string) (*oauth2.Token, error) { if authorizationCode == "" { - return nil, fmt.Errorf("invalid authorization code") + return nil, errors.New("invalid authorization code") } f, set := e.getFutureToken(authorizationCode) diff --git a/coap-gateway/service/log.go b/coap-gateway/service/log.go index 15e74d9b4..9b55c1a14 100644 --- a/coap-gateway/service/log.go +++ b/coap-gateway/service/log.go @@ -15,7 +15,7 @@ import ( const logNotificationKey = "notification" -var toNil = func(args ...interface{}) { +var toNil = func(...interface{}) { // Do nothing because we don't want to log anything } diff --git a/coap-gateway/service/mem_test.go b/coap-gateway/service/mem_test.go index 200c84728..94a502d2b 100644 --- a/coap-gateway/service/mem_test.go +++ b/coap-gateway/service/mem_test.go @@ -6,6 +6,7 @@ package service_test import ( "context" "crypto/tls" + "errors" "fmt" "os" "os/exec" @@ -221,7 +222,7 @@ func testDevices(t *testing.T, numDevices, numResources, expRSSInMB int, resourc err = cmdService.Start() require.NoError(t, err) } else { - require.NoError(t, fmt.Errorf("service process is dead - canceling test")) + require.NoError(t, errors.New("service process is dead - canceling test")) } } t.Logf("waiting for service to start: %v, serviceRSS %v\n", time.Since(now), bToMb(serviceRSS)) @@ -250,12 +251,12 @@ func testDevices(t *testing.T, numDevices, numResources, expRSSInMB int, resourc }() coapShutdown := func() { - err := s.Close() - require.NoError(t, err) + errC := s.Close() + require.NoError(t, errC) wg.Wait() } defer coapShutdown() - grpcConn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + grpcConn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/coap-gateway/service/message/response_test.go b/coap-gateway/service/message/response_test.go index c78868e94..7c8ab93d1 100644 --- a/coap-gateway/service/message/response_test.go +++ b/coap-gateway/service/message/response_test.go @@ -2,6 +2,7 @@ package message import ( "context" + "errors" "fmt" "net/http" "testing" @@ -72,7 +73,7 @@ func TestIsTempError(t *testing.T) { }, { name: "any error as temporary", - args: args{err: fmt.Errorf("any error")}, + args: args{err: errors.New("any error")}, want: true, }, { diff --git a/coap-gateway/service/observation/deviceObserver.go b/coap-gateway/service/observation/deviceObserver.go index 8eed989cd..baaf63218 100644 --- a/coap-gateway/service/observation/deviceObserver.go +++ b/coap-gateway/service/observation/deviceObserver.go @@ -15,6 +15,7 @@ import ( "github.com/plgd-dev/hub/v2/coap-gateway/resource" "github.com/plgd-dev/hub/v2/grpc-gateway/pb" "github.com/plgd-dev/hub/v2/pkg/log" + "github.com/plgd-dev/hub/v2/pkg/net/coap" pkgStrings "github.com/plgd-dev/hub/v2/pkg/strings" "github.com/plgd-dev/hub/v2/resource-aggregate/commands" pbRD "github.com/plgd-dev/hub/v2/resource-directory/pb" @@ -165,7 +166,7 @@ func WithMaxETagsCountInRequest(v uint32) MaxETagsCountInRequestOpt { } func prepareSetupDeviceObserver(ctx context.Context, deviceID string, coapConn ClientConn, rdClient GrpcGatewayClient, raClient ResourceAggregateClient, cfg DeviceObserverConfig) (DeviceObserverConfig, []*commands.Resource, error) { - links, sequence, err := GetResourceLinks(ctx, coapConn, resources.ResourceURI) + links, sequence, err := coap.GetResourceLinksWithLinkInterface(ctx, coapConn, resources.ResourceURI) switch { case err == nil: if cfg.ObservationType == ObservationType_Detect { @@ -254,8 +255,8 @@ func NewDeviceObserver(ctx context.Context, deviceID string, coapConn ClientConn if cfg.ObservationType == ObservationType_PerDevice { etags := getETags(ctx, deviceID, rdClient, cfg) - resourcesObserver, err := createDiscoveryResourceObserver(ctx, deviceID, coapConn, callbacks, etags, cfg.Logger) - if err == nil { + resourcesObserver, errC := createDiscoveryResourceObserver(ctx, deviceID, coapConn, callbacks, etags, cfg.Logger) + if errC == nil { return &DeviceObserver{ deviceID: deviceID, observationType: ObservationType_PerDevice, @@ -266,15 +267,15 @@ func NewDeviceObserver(ctx context.Context, deviceID string, coapConn ClientConn raClient: raClient, }, nil } - cfg.Logger.Debugf("NewDeviceObserver: failed to create /oic/res observation for device(%v): %v", deviceID, err) + cfg.Logger.Debugf("NewDeviceObserver: failed to create /oic/res observation for device(%v): %v", deviceID, errC) } if cfg.RequireBatchObserveEnabled { return nil, createError(fmt.Errorf("device(%v) doesn't support batch observe, which is required by configuration", deviceID)) } - resourcesObserver, err := createPublishedResourcesObserver(ctx, deviceID, coapConn, callbacks, published, cfg.Logger) - if err != nil { - return nil, createError(err) + resourcesObserver, errC := createPublishedResourcesObserver(ctx, deviceID, coapConn, callbacks, published, cfg.Logger) + if errC != nil { + return nil, createError(errC) } return &DeviceObserver{ deviceID: deviceID, @@ -288,12 +289,12 @@ func NewDeviceObserver(ctx context.Context, deviceID string, coapConn ClientConn } func emptyDeviceIDError() error { - return fmt.Errorf("empty deviceID") + return errors.New("empty deviceID") } func IsDiscoveryResourceObservable(links schema.ResourceLinks) (bool, error) { if len(links) == 0 { - return false, fmt.Errorf("no links") + return false, errors.New("no links") } resourceHref := resources.ResourceURI observeInterface := interfaces.OC_IF_B @@ -327,7 +328,7 @@ func loadTwinEnabled(ctx context.Context, rdClient GrpcGatewayClient, deviceID s return fmt.Errorf("cannot get device(%v) metadata: %w", deviceID, err) } if deviceID == "" { - return false, metadataError(fmt.Errorf("invalid deviceID")) + return false, metadataError(errors.New("invalid deviceID")) } deviceMetadataClient, err := rdClient.GetDevicesMetadata(ctx, &pb.GetDevicesMetadataRequest{ DeviceIdFilter: []string{deviceID}, @@ -412,7 +413,7 @@ func (d *DeviceObserver) GetResources() ([]*commands.ResourceId, error) { return nil, nil } if d.resourcesObserver == nil { - return nil, getResourcesError(fmt.Errorf("resources observer is nil")) + return nil, getResourcesError(errors.New("resources observer is nil")) } return d.resourcesObserver.getResources(), nil } diff --git a/coap-gateway/service/observation/deviceObserver_test.go b/coap-gateway/service/observation/deviceObserver_test.go index 31f4d9342..04e3e489a 100644 --- a/coap-gateway/service/observation/deviceObserver_test.go +++ b/coap-gateway/service/observation/deviceObserver_test.go @@ -34,6 +34,7 @@ import ( coapgwTestService "github.com/plgd-dev/hub/v2/test/coap-gateway/service" coapgwTest "github.com/plgd-dev/hub/v2/test/coap-gateway/test" "github.com/plgd-dev/hub/v2/test/config" + "github.com/plgd-dev/hub/v2/test/device/ocf" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" pbTest "github.com/plgd-dev/hub/v2/test/pb" "github.com/plgd-dev/hub/v2/test/service" @@ -121,13 +122,13 @@ func (h *observerHandler) SignIn(req coapgwService.CoapSignInReq) (coapgwService err = h.service.Submit(func() { if prevDeviceObserver != nil { - v, err := prevDeviceObserver.Get(h.ctx) - require.NoError(h.t, err) + v, errD := prevDeviceObserver.Get(h.ctx) + require.NoError(h.t, errD) obs := v.(*observation.DeviceObserver) obs.Clean(h.ctx) } - deviceObserver, err := h.deviceObserverFactory.makeDeviceObserver(h.ctx, h.coapConn, h.OnObserveResource, h.OnGetResourceContent, h.UpdateTwinSynchronizationStatus, observation.WithRequireBatchObserveEnabled(h.requireBatchObserveEnabled)) - require.NoError(h.t, err) + deviceObserver, errD := h.deviceObserverFactory.makeDeviceObserver(h.ctx, h.coapConn, h.OnObserveResource, h.OnGetResourceContent, h.UpdateTwinSynchronizationStatus, observation.WithRequireBatchObserveEnabled(h.requireBatchObserveEnabled)) + require.NoError(h.t, errD) setDeviceObserver(deviceObserver, nil) }) require.NoError(h.t, err) @@ -160,8 +161,8 @@ func (h *observerHandler) PublishResources(req coapgwTestService.PublishRequest) return nil } -func (h *observerHandler) OnObserveResource(ctx context.Context, deviceID, resourceHref string, _ bool, notification *pool.Message) error { - err := h.DefaultObserverHandler.OnObserveResource(ctx, deviceID, resourceHref, notification) +func (h *observerHandler) OnObserveResource(ctx context.Context, deviceID, resourceHref string, resourceTypes []string, _ bool, notification *pool.Message) error { + err := h.DefaultObserverHandler.OnObserveResource(ctx, deviceID, resourceHref, resourceTypes, notification) require.NoError(h.t, err) if !h.done.Load() { h.observedResourceChan <- commands.NewResourceID(deviceID, resourceHref) @@ -169,8 +170,8 @@ func (h *observerHandler) OnObserveResource(ctx context.Context, deviceID, resou return nil } -func (h *observerHandler) OnGetResourceContent(ctx context.Context, deviceID, resourceHref string, notification *pool.Message) error { - err := h.DefaultObserverHandler.OnGetResourceContent(ctx, deviceID, resourceHref, notification) +func (h *observerHandler) OnGetResourceContent(ctx context.Context, deviceID, resourceHref string, resourceTypes []string, notification *pool.Message) error { + err := h.DefaultObserverHandler.OnGetResourceContent(ctx, deviceID, resourceHref, resourceTypes, notification) require.NoError(h.t, err) if !h.done.Load() { h.retrievedResourceChan <- commands.NewResourceID(deviceID, resourceHref) @@ -198,19 +199,19 @@ func TestDeviceObserverRegisterForPublishedResources(t *testing.T) { require.Equal(t, observation.ObservationType_PerResource, obs.GetObservationType()) res, err := obs.GetResources() require.NoError(t, err) - pbTest.CmpResourceIds(t, test.ResourceLinksToResourceIds(deviceID, test.TestDevsimResources), res) + pbTest.CmpResourceIds(t, test.ResourceLinksToResourceIds(deviceID, test.GetAllBackendResourceLinks()), res) } expectedObserved := strings.MakeSet() for _, resID := range test.ResourceLinksToResourceIds(deviceID, test.FilterResourceLink(func(rl schema.ResourceLink) bool { return rl.Policy.BitMask.Has(schema.Observable) - }, test.TestDevsimResources)) { + }, test.GetAllBackendResourceLinks())) { expectedObserved.Add(resID.ToString()) } expectedRetrieved := strings.MakeSet() for _, resID := range test.ResourceLinksToResourceIds(deviceID, test.FilterResourceLink(func(rl schema.ResourceLink) bool { return !rl.Policy.BitMask.Has(schema.Observable) - }, test.TestDevsimResources)) { + }, test.GetAllBackendResourceLinks())) { expectedRetrieved.Add(resID.ToString()) } runTestDeviceObserverRegister(ctx, t, deviceID, expectedObserved, expectedRetrieved, validateData, nil, nil, false) @@ -230,19 +231,19 @@ func TestDeviceObserverRegisterForPublishedResourcesWithAlreadyPublishedResource require.Equal(t, observation.ObservationType_PerResource, obs.GetObservationType()) res, err := obs.GetResources() require.NoError(t, err) - pbTest.CmpResourceIds(t, test.ResourceLinksToResourceIds(deviceID, test.TestDevsimResources), res) + pbTest.CmpResourceIds(t, test.ResourceLinksToResourceIds(deviceID, test.GetAllBackendResourceLinks()), res) } expectedObserved := strings.MakeSet() for _, resID := range test.ResourceLinksToResourceIds(deviceID, test.FilterResourceLink(func(rl schema.ResourceLink) bool { return rl.Policy.BitMask.Has(schema.Observable) - }, test.TestDevsimResources)) { + }, test.GetAllBackendResourceLinks())) { expectedObserved.Add(resID.ToString()) } expectedRetrieved := strings.MakeSet() for _, resID := range test.ResourceLinksToResourceIds(deviceID, test.FilterResourceLink(func(rl schema.ResourceLink) bool { return !rl.Policy.BitMask.Has(schema.Observable) - }, test.TestDevsimResources)) { + }, test.GetAllBackendResourceLinks())) { expectedRetrieved.Add(resID.ToString()) } runTestDeviceObserverRegister(ctx, t, deviceID, expectedObserved, expectedRetrieved, validateData, testPreregisterVirtualDevice, testValidateResourceLinks, false) @@ -270,7 +271,7 @@ func TestDeviceObserverRegisterForDiscoveryResource(t *testing.T) { } func testPreregisterVirtualDevice(ctx context.Context, t *testing.T, deviceID string, grpcClient pb.GrpcGatewayClient, raClient raPb.ResourceAggregateClient) { - isConn, err := grpc.Dial(config.IDENTITY_STORE_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + isConn, err := grpc.NewClient(config.IDENTITY_STORE_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -298,14 +299,14 @@ func testPreregisterVirtualDevice(ctx context.Context, t *testing.T, deviceID st ev, err := client.Recv() require.NoError(t, err) require.NotEmpty(t, ev.GetOperationProcessed()) - require.Equal(t, ev.GetOperationProcessed().GetErrorStatus().GetCode(), pb.Event_OperationProcessed_ErrorStatus_OK) - virtualdevice.CreateDevice(ctx, t, "name-"+deviceID, deviceID, numResources, test.StringToApplicationProtocol(config.ACTIVE_COAP_SCHEME), isClient, raClient) - resources := virtualdevice.CreateDeviceResourceLinks(deviceID, numResources) + require.Equal(t, pb.Event_OperationProcessed_ErrorStatus_OK, ev.GetOperationProcessed().GetErrorStatus().GetCode()) + virtualdevice.CreateDevice(ctx, t, "name-"+deviceID, deviceID, numResources, false, test.StringToApplicationProtocol(config.ACTIVE_COAP_SCHEME), isClient, raClient) + resources := virtualdevice.CreateDeviceResourceLinks(deviceID, numResources, false) links := make([]schema.ResourceLink, 0, len(resources)) for _, r := range resources { links = append(links, r.ToSchema()) } - test.WaitForDevice(t, client, deviceID, ev.GetSubscriptionId(), ev.GetCorrelationId(), links) + test.WaitForDevice(t, client, ocf.NewDevice(deviceID, test.TestDeviceName), ev.GetSubscriptionId(), ev.GetCorrelationId(), links) } func testValidateResourceLinks(ctx context.Context, t *testing.T, deviceID string, grpcClient pb.GrpcGatewayClient, _ raPb.ResourceAggregateClient) { @@ -451,7 +452,7 @@ func runTestDeviceObserverRegister(ctx context.Context, t *testing.T, deviceID s coapShutdown := coapgwTest.SetUp(t, makeHandler, validateHandler) defer coapShutdown() - grpcConn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + grpcConn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/coap-gateway/service/observation/observation.go b/coap-gateway/service/observation/observation.go deleted file mode 100644 index 6d8caf9b1..000000000 --- a/coap-gateway/service/observation/observation.go +++ /dev/null @@ -1,42 +0,0 @@ -package observation - -import ( - "context" - "fmt" - - "github.com/plgd-dev/device/v2/schema" - "github.com/plgd-dev/device/v2/schema/interfaces" - coapMessage "github.com/plgd-dev/go-coap/v3/message" - "github.com/plgd-dev/go-coap/v3/message/codes" - "github.com/plgd-dev/hub/v2/coap-gateway/uri" - "github.com/plgd-dev/kit/v2/codec/cbor" -) - -// Query resource links from the given resource with the interface oic.if.ll. -func GetResourceLinks(ctx context.Context, coapConn ClientConn, href string) (schema.ResourceLinks, uint64, error) { - msg, err := coapConn.Get(ctx, href, coapMessage.Option{ - ID: coapMessage.URIQuery, - Value: []byte(uri.InterfaceQueryKeyPrefix + interfaces.OC_IF_LL), - }) - if err != nil { - return schema.ResourceLinks{}, 0, err - } - defer coapConn.ReleaseMessage(msg) - - if msg.Code() != codes.Content { - return schema.ResourceLinks{}, 0, fmt.Errorf("invalid response code %v", msg.Code()) - } - - data := msg.Body() - if data == nil { - return schema.ResourceLinks{}, 0, fmt.Errorf("empty response") - } - - var links schema.ResourceLinks - err = cbor.ReadFrom(msg.Body(), &links) - if err != nil { - return schema.ResourceLinks{}, 0, err - } - - return links, msg.Sequence(), nil -} diff --git a/coap-gateway/service/observation/observation_test.go b/coap-gateway/service/observation/observation_test.go index 0e9b4c4a5..f8f88c16d 100644 --- a/coap-gateway/service/observation/observation_test.go +++ b/coap-gateway/service/observation/observation_test.go @@ -11,6 +11,7 @@ import ( coapgwService "github.com/plgd-dev/hub/v2/coap-gateway/service" "github.com/plgd-dev/hub/v2/coap-gateway/service/observation" "github.com/plgd-dev/hub/v2/grpc-gateway/pb" + "github.com/plgd-dev/hub/v2/pkg/net/coap" kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc" "github.com/plgd-dev/hub/v2/pkg/sync/task/future" "github.com/plgd-dev/hub/v2/test" @@ -51,7 +52,7 @@ func TestIsResourceObservableWithInterface(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) handlerFuture, setHandler := future.New() - makeHandler := func(service *coapgwTestService.Service, opts ...coapgwTestService.Option) coapgwTestService.ServiceHandler { + makeHandler := func(_ *coapgwTestService.Service, opts ...coapgwTestService.Option) coapgwTestService.ServiceHandler { cfg := coapgwTestService.ServiceHandlerConfig{} for _, o := range opts { o.Apply(&cfg) @@ -68,7 +69,7 @@ func TestIsResourceObservableWithInterface(t *testing.T) { coapShutdown := coapgwTest.SetUp(t, makeHandler, nil) defer coapShutdown() - grpcConn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + grpcConn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -116,7 +117,7 @@ func TestIsResourceObservableWithInterface(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - links, _, err := observation.GetResourceLinks(ctx, handler.coapConn, tt.args.href) + links, _, err := coap.GetResourceLinksWithLinkInterface(ctx, handler.coapConn, tt.args.href) if tt.wantErr { require.Error(t, err) return diff --git a/coap-gateway/service/observation/observedResource.go b/coap-gateway/service/observation/observedResource.go index 560b72aab..2f269a5f1 100644 --- a/coap-gateway/service/observation/observedResource.go +++ b/coap-gateway/service/observation/observedResource.go @@ -20,21 +20,23 @@ type Observation = interface { // Thread-safe wrapper with additional data for *tcp.Observation. type observedResource struct { - href string - resInterface string - synced atomic.Bool - isObservable bool - private struct { // guarded by mutex + href string + resInterface string + synced atomic.Bool + isObservable bool + resourceTypes []string + private struct { // guarded by mutex mutex sync.Mutex observation Observation } } -func newObservedResource(href, resInterface string, isObservable bool) *observedResource { +func newObservedResource(href, resInterface string, isObservable bool, resourceTypes []string) *observedResource { return &observedResource{ - href: href, - resInterface: resInterface, - isObservable: isObservable, + href: href, + resInterface: resInterface, + isObservable: isObservable, + resourceTypes: resourceTypes, } } diff --git a/coap-gateway/service/observation/resourcesObserver.go b/coap-gateway/service/observation/resourcesObserver.go index ffe438afe..e8897ac1c 100644 --- a/coap-gateway/service/observation/resourcesObserver.go +++ b/coap-gateway/service/observation/resourcesObserver.go @@ -2,6 +2,7 @@ package observation import ( "context" + "errors" "fmt" "sync" "time" @@ -15,8 +16,8 @@ import ( ) type ( - OnObserveResource = func(ctx context.Context, deviceID, resourceHref string, batch bool, notification *pool.Message) error - OnGetResourceContent = func(ctx context.Context, deviceID, resourceHref string, notification *pool.Message) error + OnObserveResource = func(ctx context.Context, deviceID, resourceHref string, resourceTypes []string, batch bool, notification *pool.Message) error + OnGetResourceContent = func(ctx context.Context, deviceID, resourceHref string, resourceTypes []string, notification *pool.Message) error UpdateTwinSynchronization = func(ctx context.Context, deviceID string, status commands.TwinSynchronization_State, t time.Time) error ) @@ -68,13 +69,13 @@ func newResourcesObserver(deviceID string, coapConn ClientConn, callbacks Resour fatalCannotCreate(emptyDeviceIDError()) } if coapConn == nil { - fatalCannotCreate(fmt.Errorf("invalid coap-gateway connection")) + fatalCannotCreate(errors.New("invalid coap-gateway connection")) } if callbacks.OnObserveResource == nil { - fatalCannotCreate(fmt.Errorf("invalid onObserveResource callback")) + fatalCannotCreate(errors.New("invalid onObserveResource callback")) } if callbacks.OnGetResourceContent == nil { - fatalCannotCreate(fmt.Errorf("invalid onGetResourceContent callback")) + fatalCannotCreate(errors.New("invalid onGetResourceContent callback")) } return &resourcesObserver{ deviceID: deviceID, @@ -124,15 +125,13 @@ func (o *resourcesObserver) setSynchronizedAtResource(href string) bool { o.private.lock.Lock() defer o.private.lock.Unlock() i := o.private.resources.search(href) - synced := false if i < len(o.private.resources) && o.private.resources[i].Equals(href) { - synced = o.private.resources[i].synced.CompareAndSwap(false, true) + if !o.private.resources[i].synced.CompareAndSwap(false, true) { + return false + } } else { return false } - if !synced { - return false - } if o.isSynchronizedLocked() { return true } @@ -154,7 +153,7 @@ func (o *resourcesObserver) addResourceLocked(res *commands.Resource, obsInterfa if o.private.resources.contains(href) { return nil, nil } - obsRes := newObservedResource(href, obsInterface, res.IsObservable()) + obsRes := newObservedResource(href, obsInterface, res.IsObservable(), res.GetResourceTypes()) o.private.resources = o.private.resources.insert(obsRes) return obsRes, nil } @@ -180,7 +179,7 @@ func (o *resourcesObserver) handleResource(ctx context.Context, obsRes *observed if len(etags) > 0 { etag = etags[0] } - return o.getResourceContent(ctx, obsRes.Href(), etag) + return o.getResourceContent(ctx, obsRes.Href(), obsRes.resourceTypes, etag) } // Register to COAP-GW resource observation for given resource @@ -204,7 +203,7 @@ func (o *resourcesObserver) observeResource(ctx context.Context, obsRes *observe } } - if err2 := o.callbacks.OnObserveResource(ctx, o.deviceID, obsRes.Href(), batchObservation, msg); err2 != nil { + if err2 := o.callbacks.OnObserveResource(ctx, o.deviceID, obsRes.Href(), obsRes.resourceTypes, batchObservation, msg); err2 != nil { _ = o.logger.LogAndReturnError(cannotObserveResourceError(o.deviceID, obsRes.Href(), err2)) return } @@ -213,13 +212,13 @@ func (o *resourcesObserver) observeResource(ctx context.Context, obsRes *observe return nil, cannotObserveResourceError(o.deviceID, obsRes.Href(), err) } if obs.Canceled() { - return nil, cannotObserveResourceError(o.deviceID, obsRes.Href(), fmt.Errorf("resource not observable")) + return nil, cannotObserveResourceError(o.deviceID, obsRes.Href(), errors.New("resource not observable")) } return obs, nil } // Request resource content form COAP-GW -func (o *resourcesObserver) getResourceContent(ctx context.Context, href string, etag []byte) error { +func (o *resourcesObserver) getResourceContent(ctx context.Context, href string, resourceTypes []string, etag []byte) error { cannotGetResourceError := func(deviceID, href string, err error) error { return fmt.Errorf("cannot get resource /%v%v content: %w", deviceID, href, err) } @@ -243,7 +242,7 @@ func (o *resourcesObserver) getResourceContent(ctx context.Context, href string, o.coapConn.ReleaseMessage(resp) } }() - if err := o.callbacks.OnGetResourceContent(ctx, o.deviceID, href, resp); err != nil { + if err := o.callbacks.OnGetResourceContent(ctx, o.deviceID, href, resourceTypes, resp); err != nil { return cannotGetResourceError(o.deviceID, href, err) } return nil @@ -373,8 +372,8 @@ func (o *resourcesObserver) CleanObservedResources(ctx context.Context) { } func (o *resourcesObserver) cleanObservedResourcesLocked(ctx context.Context) { - observedResources := o.popObservedResourcesLocked() - for _, obs := range observedResources { + ors := o.popObservedResourcesLocked() + for _, obs := range ors { if v := obs.PopObservation(); v != nil { if err := v.Cancel(ctx); err != nil { o.logger.Errorf("cannot cancel resource('/%v%v') observation: %w", o.deviceID, obs.Href(), err) diff --git a/coap-gateway/service/refreshCache.go b/coap-gateway/service/refreshCache.go index 338554213..39531da0e 100644 --- a/coap-gateway/service/refreshCache.go +++ b/coap-gateway/service/refreshCache.go @@ -2,7 +2,7 @@ package service import ( "context" - "fmt" + "errors" "sync" "github.com/plgd-dev/hub/v2/pkg/log" @@ -66,7 +66,7 @@ func refresh(ctx context.Context, providers map[string]*oauth2.PlgdProvider, que return nil, err } - return nil, fmt.Errorf("invalid token") + return nil, errors.New("invalid token") } func (r *RefreshCache) getFutureToken(refreshToken string) (*future.Future, future.SetFunc) { @@ -83,7 +83,7 @@ func (r *RefreshCache) getFutureToken(refreshToken string) (*future.Future, futu func (r *RefreshCache) Execute(ctx context.Context, providers map[string]*oauth2.PlgdProvider, queue *queue.Queue, refreshToken string, logger log.Logger) (*oauth2.Token, error) { if refreshToken == "" { - return nil, fmt.Errorf("invalid refreshToken") + return nil, errors.New("invalid refreshToken") } f, set := r.getFutureToken(refreshToken) diff --git a/coap-gateway/service/refreshToken.go b/coap-gateway/service/refreshToken.go index a818c795b..df1347b21 100644 --- a/coap-gateway/service/refreshToken.go +++ b/coap-gateway/service/refreshToken.go @@ -117,7 +117,7 @@ func getRefreshTokenDataFromClaims(ctx context.Context, client *session, accessT owner = req.UserID } if owner == "" { - return "", "", fmt.Errorf("cannot determine owner") + return "", "", errors.New("cannot determine owner") } return deviceID, owner, nil } @@ -149,7 +149,7 @@ func refreshTokenPostHandler(req *mux.Message, client *session) (*pool.Message, } if token.RefreshToken == "" { - return nil, statusErrorf(coapCodes.Unauthorized, "%w", fmt.Errorf(fmtErr, refreshToken.DeviceID, fmt.Errorf("refresh didn't return a refresh token"))) + return nil, statusErrorf(coapCodes.Unauthorized, "%w", fmt.Errorf(fmtErr, refreshToken.DeviceID, errors.New("refresh didn't return a refresh token"))) } deviceID, owner, err := getRefreshTokenDataFromClaims(req.Context(), client, token.AccessToken.String(), refreshToken) @@ -163,12 +163,12 @@ func refreshTokenPostHandler(req *mux.Message, client *session) (*pool.Message, return nil, statusErrorf(coapCodes.Unauthorized, "%w", fmt.Errorf(fmtErr, deviceID, fmt.Errorf("cannot check owning: %w", err))) } if !ok { - return nil, statusErrorf(coapCodes.Unauthorized, "%w", fmt.Errorf(fmtErr, deviceID, fmt.Errorf("device is not registered"))) + return nil, statusErrorf(coapCodes.Unauthorized, "%w", fmt.Errorf(fmtErr, deviceID, errors.New("device is not registered"))) } expire, ok := ValidUntil(token.Expiry) if !ok { - return nil, statusErrorf(coapCodes.Unauthorized, "%w", fmt.Errorf(fmtErr, deviceID, fmt.Errorf("expired access token"))) + return nil, statusErrorf(coapCodes.Unauthorized, "%w", fmt.Errorf(fmtErr, deviceID, errors.New("expired access token"))) } validUntil := pkgTime.Unix(0, expire) diff --git a/coap-gateway/service/resourceDirectory.go b/coap-gateway/service/resourceDirectory.go index 3d4b26971..61c6a8dcb 100644 --- a/coap-gateway/service/resourceDirectory.go +++ b/coap-gateway/service/resourceDirectory.go @@ -146,7 +146,7 @@ func observeResources(ctx context.Context, client *session, w wkRd, sequenceNumb return } if !ok { - x.client.Errorf("%w", x.observeError(x.w.DeviceID, fmt.Errorf("cannot get device observer"))) + x.client.Errorf("%w", x.observeError(x.w.DeviceID, errors.New("cannot get device observer"))) return } if errObs := obs.AddPublishedResources(x.ctx, x.publishedResources); errObs != nil { @@ -170,8 +170,8 @@ func resourceDirectoryPublishHandler(req *mux.Message, client *session) (*pool.M return nil, statusErrorf(coapCodes.BadRequest, "%w", err) } - if errCode, err := observeResources(req.Context(), client, w, req.Sequence()); err != nil { - return nil, statusErrorf(errCode, "%w", err) + if errCode, errO := observeResources(req.Context(), client, w, req.Sequence()); errO != nil { + return nil, statusErrorf(errCode, "%w", errO) } accept := coapconv.GetAccept(req.Options()) @@ -193,11 +193,13 @@ func parseUnpublishQueryString(queries []string) (deviceID string, instanceIDs [ if err != nil { return "", nil, fmt.Errorf("cannot parse unpublish query: %w", err) } - if di := values.Get("di"); di != "" { + for _, di := range values["di"] { + if deviceID != "" { + return "", nil, fmt.Errorf("unable to parse unpublish query: duplicate in parameter di(%v), previously di(%v)", di, deviceID) + } deviceID = di } - - if ins := values.Get("ins"); ins != "" { + for _, ins := range values["ins"] { i, err := strconv.Atoi(ins) if err != nil { return "", nil, fmt.Errorf("cannot convert %v to number", ins) @@ -207,7 +209,7 @@ func parseUnpublishQueryString(queries []string) (deviceID string, instanceIDs [ } if deviceID == "" { - return "", nil, fmt.Errorf("deviceID not found") + return "", nil, errors.New("deviceID not found") } return diff --git a/coap-gateway/service/resourceDirectory_internal_test.go b/coap-gateway/service/resourceDirectory_internal_test.go new file mode 100644 index 000000000..5cf9ef032 --- /dev/null +++ b/coap-gateway/service/resourceDirectory_internal_test.go @@ -0,0 +1,71 @@ +//go:build test +// +build test + +package service + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseUnpublishQueryString(t *testing.T) { + tests := []struct { + name string + queries []string + expectedID string + expectedIns []int64 + wantErr bool + }{ + { + name: "ValidQueries", + queries: []string{"di=device1", "ins=1", "ins=2"}, + expectedID: "device1", + expectedIns: []int64{1, 2}, + }, + { + name: "MultipleInsInOneQuery", + queries: []string{"di=device1&ins=1&ins=2"}, + expectedID: "device1", + expectedIns: []int64{1, 2}, + }, + { + name: "InvalidIns", + queries: []string{"di=device1", "ins=abc"}, + wantErr: true, + }, + { + name: "One of the queries is invalid", + queries: []string{"di=device1", "ins=1", "invalid_query"}, + expectedID: "device1", + expectedIns: []int64{1}, + }, + { + name: "MultipleDeviceIDs", + queries: []string{"di=device1&di=device2"}, + wantErr: true, + }, + { + name: "DeviceIDandInsAreNotSet", + queries: []string{"invalidQuery=123"}, + wantErr: true, + }, + { + name: "EmptyQueries", + queries: []string{}, + wantErr: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + deviceID, instanceIDs, err := parseUnpublishQueryString(test.queries) + if test.wantErr { + require.Error(t, err) + return + } + require.Equal(t, test.expectedID, deviceID) + require.Equal(t, test.expectedIns, instanceIDs) + }) + } +} diff --git a/coap-gateway/service/service.go b/coap-gateway/service/service.go index 4ce87f54e..e01492659 100644 --- a/coap-gateway/service/service.go +++ b/coap-gateway/service/service.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "crypto/x509" + "errors" "fmt" "net" "os" @@ -291,7 +292,7 @@ func New(ctx context.Context, config Config, fileWatcher *fsnotify.Watcher, logg if firstProvider == nil { nats.Close() - return nil, fmt.Errorf("device providers are empty") + return nil, errors.New("device providers are empty") } keyCache := jwt.NewKeyCache(firstProvider.OpenID.JWKSURL, firstProvider.HTTP()) @@ -357,7 +358,7 @@ func onUnprocessedRequestError(code coapCodes.Code) error { if code == coapCodes.Content { errMsg = "notification from client was dropped" } - return fmt.Errorf(errMsg) + return errors.New(errMsg) } func wantToCloseClientOnError(req *mux.Message) bool { @@ -391,7 +392,7 @@ func (s *Service) processCommandTask(req *mux.Message, client *session, span tra }() } default: - err := onUnprocessedRequestError(req.Code()) + err = onUnprocessedRequestError(req.Code()) client.logRequestResponse(req, nil, err) span.RecordError(err) span.SetStatus(otelCodes.Error, err.Error()) @@ -449,7 +450,7 @@ func executeCommand(s mux.ResponseWriter, req *mux.Message, server *Service, fnc if !ok { client = newSession(server, s.Conn(), "", time.Time{}) if req.Code() == coapCodes.Empty { - client.logRequestResponse(req, nil, fmt.Errorf("cannot handle command: client not found")) + client.logRequestResponse(req, nil, errors.New("cannot handle command: client not found")) client.Close() return } @@ -495,25 +496,27 @@ func getTLSInfo(conn net.Conn, logger log.Logger) (deviceID string, validUntil t logger.Debugf("cannot get deviceID from certificate: certificate is not set") return "", time.Time{} } - if tlsCon, ok := conn.(*dtls.Conn); ok { - peerCertificates := tlsCon.ConnectionState().PeerCertificates - if len(peerCertificates) > 0 { - cert, err := x509.ParseCertificate(peerCertificates[0]) - if err != nil { - logger.Warnf("cannot get deviceID from certificate: %w", err) - return "", time.Time{} - } - deviceID, err := coap.GetDeviceIDFromIdentityCertificate(cert) - if err == nil { - return deviceID, cert.NotAfter - } - logger.Warnf("cannot get deviceID from certificate %v: %w", cert.Subject.CommonName, err) - return "", cert.NotAfter - } - logger.Debugf("cannot get deviceID from certificate: certificate is not set") + + tlsCon, ok := conn.(*dtls.Conn) + if !ok { + logger.Debugf("cannot get deviceID from certificate: unsupported connection type") return "", time.Time{} } - logger.Debugf("cannot get deviceID from certificate: unsupported connection type") + peerCertificates := tlsCon.ConnectionState().PeerCertificates + if len(peerCertificates) > 0 { + cert, err := x509.ParseCertificate(peerCertificates[0]) + if err != nil { + logger.Warnf("cannot get deviceID from certificate: %w", err) + return "", time.Time{} + } + deviceID, err := coap.GetDeviceIDFromIdentityCertificate(cert) + if err == nil { + return deviceID, cert.NotAfter + } + logger.Warnf("cannot get deviceID from certificate %v: %w", cert.Subject.CommonName, err) + return "", cert.NotAfter + } + logger.Debugf("cannot get deviceID from certificate: certificate is not set") return "", time.Time{} } diff --git a/coap-gateway/service/service_test.go b/coap-gateway/service/service_test.go index 4adc86f91..c705725fa 100644 --- a/coap-gateway/service/service_test.go +++ b/coap-gateway/service/service_test.go @@ -97,7 +97,7 @@ func TestShutdownServiceWithDeviceIssue627(t *testing.T) { coapShutdown := coapgwTest.SetUp(t) defer coapShutdown() - grpcConn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + grpcConn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/coap-gateway/service/session.go b/coap-gateway/service/session.go index 8943cc59c..b4f7f7803 100644 --- a/coap-gateway/service/session.go +++ b/coap-gateway/service/session.go @@ -25,6 +25,7 @@ import ( "github.com/plgd-dev/hub/v2/grpc-gateway/pb" idEvents "github.com/plgd-dev/hub/v2/identity-store/events" "github.com/plgd-dev/hub/v2/pkg/log" + "github.com/plgd-dev/hub/v2/pkg/net/coap" coapService "github.com/plgd-dev/hub/v2/pkg/net/coap/service" kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc" "github.com/plgd-dev/hub/v2/pkg/opentelemetry/otelcoap" @@ -81,13 +82,13 @@ func (a *authorizationContext) GetJWTClaims() pkgJwt.Claims { func (a *authorizationContext) IsValid() error { if a == nil { - return fmt.Errorf("invalid authorization context") + return errors.New("invalid authorization context") } if a.AccessToken == "" { - return fmt.Errorf("invalid access token") + return errors.New("invalid access token") } if !a.Expire.IsZero() && time.Now().UnixNano() > a.Expire.UnixNano() { - return fmt.Errorf("token is expired") + return errors.New("token is expired") } return nil } @@ -316,7 +317,7 @@ func (c *session) cancelResourceSubscription(token string) (bool, error) { // // The received notification is released by this function at the correct moment and must not be released // by the caller. -func (c *session) onGetResourceContent(ctx context.Context, deviceID, href string, notification *pool.Message) error { +func (c *session) onGetResourceContent(ctx context.Context, deviceID, href string, resourceTypes []string, notification *pool.Message) error { cannotGetResourceContentError := func(deviceID, href string, err error) error { return fmt.Errorf("cannot get resource /%v%v content: %w", deviceID, href, err) } @@ -326,6 +327,7 @@ func (c *session) onGetResourceContent(ctx context.Context, deviceID, href strin notification *pool.Message deviceID string href string + resourceTypes []string c *session cannotGetResourceContentError func(deviceID, href string, err error) error }{ @@ -333,6 +335,7 @@ func (c *session) onGetResourceContent(ctx context.Context, deviceID, href strin notification: notification, deviceID: deviceID, href: href, + resourceTypes: resourceTypes, c: c, cannotGetResourceContentError: cannotGetResourceContentError, } @@ -341,7 +344,7 @@ func (c *session) onGetResourceContent(ctx context.Context, deviceID, href strin if x.notification.Code() == codes.NotFound { x.c.unpublishResourceLinks(x.c.getUserAuthorizedContext(x.ctx), []string{x.href}, nil) } - err2 := x.c.notifyContentChanged(x.deviceID, x.href, false, x.notification) + err2 := x.c.notifyContentChanged(x.deviceID, x.href, x.resourceTypes, false, x.notification) if err2 != nil { // hub is out of sync with the device, for recovery, the device is disconnected from the hub x.c.Close() @@ -369,7 +372,7 @@ func (c *session) onGetResourceContent(ctx context.Context, deviceID, href strin // // The received notification is released by this function at the correct moment and must not be released // by the caller. -func (c *session) onObserveResource(ctx context.Context, deviceID, href string, batch bool, notification *pool.Message) error { +func (c *session) onObserveResource(ctx context.Context, deviceID, href string, resourceTypes []string, batch bool, notification *pool.Message) error { cannotObserResourceError := func(err error) error { return fmt.Errorf("cannot handle resource observation: %w", err) } @@ -379,6 +382,7 @@ func (c *session) onObserveResource(ctx context.Context, deviceID, href string, notification *pool.Message deviceID string href string + resourceTypes []string c *session cannotObserResourceError func(err error) error batch bool @@ -387,6 +391,7 @@ func (c *session) onObserveResource(ctx context.Context, deviceID, href string, notification: notification, deviceID: deviceID, href: href, + resourceTypes: resourceTypes, c: c, cannotObserResourceError: cannotObserResourceError, batch: batch, @@ -396,7 +401,7 @@ func (c *session) onObserveResource(ctx context.Context, deviceID, href string, if x.notification.Code() == codes.NotFound { x.c.unpublishResourceLinks(x.c.getUserAuthorizedContext(x.notification.Context()), []string{x.href}, nil) } - err2 := x.c.notifyContentChanged(x.deviceID, x.href, x.batch, x.notification) + err2 := x.c.notifyContentChanged(x.deviceID, x.href, x.resourceTypes, x.batch, x.notification) if err2 != nil { // hub is out of sync with the device, for recovery, the device is disconnected from the hub x.c.Close() @@ -516,7 +521,17 @@ func (c *session) batchNotifyContentChanged(ctx context.Context, deviceID string return err } -func (c *session) notifyContentChanged(deviceID, href string, batch bool, notification *pool.Message) error { +func (c *session) getLocalEndpoints() []string { + localEndpoints, err := coap.GetEndpointsFromDeviceResource(c.Context(), c) + if err != nil { + c.getLogger().Warnf("cannot get local endpoints: %v", err) + return nil + } + c.getLogger().With(log.LocalEndpointsKey, localEndpoints).Debugf("local endpoints retrieval successful.") + return localEndpoints +} + +func (c *session) notifyContentChanged(deviceID, href string, resourceTypes []string, batch bool, notification *pool.Message) error { if !c.blockSignOff.TryAcquire(1) { c.getLogger().Debugf("cannot notify resource /%v%v content changed: signOff processing", deviceID, href) return nil @@ -550,7 +565,7 @@ func (c *session) notifyContentChanged(deviceID, href string, batch bool, notifi } return nil } - _, err = c.server.raClient.NotifyResourceChanged(ctx, coapconv.NewNotifyResourceChangedRequest(commands.NewResourceID(deviceID, href), c.RemoteAddr().String(), notification)) + _, err = c.server.raClient.NotifyResourceChanged(ctx, coapconv.NewNotifyResourceChangedRequest(commands.NewResourceID(deviceID, href), resourceTypes, c.RemoteAddr().String(), notification)) if err != nil { return notifyError(deviceID, href, err) } @@ -816,21 +831,21 @@ func (c *session) unpublishResourceLinks(ctx context.Context, hrefs []string, in return nil } - if len(resp.UnpublishedHrefs) == 0 { + if len(resp.GetUnpublishedHrefs()) == 0 { return nil } observer, ok, err := c.getDeviceObserver(ctx) if err != nil { logUnpublishError(err) - return resp.UnpublishedHrefs + return resp.GetUnpublishedHrefs() } if !ok { - logUnpublishError(fmt.Errorf("device observer not found")) - return resp.UnpublishedHrefs + logUnpublishError(errors.New("device observer not found")) + return resp.GetUnpublishedHrefs() } - observer.RemovePublishedResources(ctx, resp.UnpublishedHrefs) - return resp.UnpublishedHrefs + observer.RemovePublishedResources(ctx, resp.GetUnpublishedHrefs()) + return resp.GetUnpublishedHrefs() } func (c *session) sendErrorConfirmResourceCreate(ctx context.Context, resourceID *commands.ResourceId, correlationID string, code codes.Code, errToSend error) { diff --git a/coap-gateway/service/signIn.go b/coap-gateway/service/signIn.go index d50380bb4..fcf6ff884 100644 --- a/coap-gateway/service/signIn.go +++ b/coap-gateway/service/signIn.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "time" @@ -33,13 +34,13 @@ type CoapSignInResp struct { // Check that all required request fields are set func (request CoapSignInReq) checkOAuthRequest() error { if request.DeviceID == "" { - return fmt.Errorf("invalid device id") + return errors.New("invalid device id") } if request.UserID == "" { - return fmt.Errorf("invalid user id") + return errors.New("invalid user id") } if request.AccessToken == "" { - return fmt.Errorf("invalid access token") + return errors.New("invalid access token") } return nil } @@ -169,10 +170,10 @@ func subscribeToDeviceEvents(client *session, owner, deviceID string) error { if evt == nil { return } - if evt.Owner != owner { + if evt.GetOwner() != owner { return } - if !strings.Contains(evt.DeviceIds, deviceID) { + if !strings.Contains(evt.GetDeviceIds(), deviceID) { return } client.Close() @@ -217,7 +218,7 @@ func getSignInDataFromClaims(ctx context.Context, client *session, signIn CoapSi return "", time.Time{}, err } - if err := jwtClaims.ValidateOwnerClaim(client.server.config.APIs.COAP.Authorization.OwnerClaim, signIn.UserID); err != nil { + if err = jwtClaims.ValidateOwnerClaim(client.server.config.APIs.COAP.Authorization.OwnerClaim, signIn.UserID); err != nil { return "", time.Time{}, err } @@ -229,7 +230,11 @@ func getSignInDataFromClaims(ctx context.Context, client *session, signIn CoapSi expTime, _ := jwtClaims.GetExpirationTime() validUntil := time.Time{} if expTime != nil { - validUntil = expTime.Time + if time.Until(expTime.Time) < 2*client.server.config.APIs.COAP.OwnerCacheExpiration { + return "", time.Time{}, fmt.Errorf("access token will expire (%v) in less time than the interval for checking expiration (%v)", expTime.Time, 2*client.server.config.APIs.COAP.OwnerCacheExpiration) + } + // set expiration time before token expiration to allow sign off device. + validUntil = expTime.Time.Add(-2 * client.server.config.APIs.COAP.OwnerCacheExpiration) } return deviceID, validUntil, nil diff --git a/coap-gateway/service/signIn_test.go b/coap-gateway/service/signIn_test.go index bdc02be8d..c93de8701 100644 --- a/coap-gateway/service/signIn_test.go +++ b/coap-gateway/service/signIn_test.go @@ -7,7 +7,6 @@ import ( "context" "crypto/tls" "errors" - "fmt" "strings" "testing" "time" @@ -75,7 +74,7 @@ func TestSignInDeviceSubscriptionHandler(t *testing.T) { defer shutdown() ctx := kitNetGrpc.CtxWithToken(context.Background(), oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -159,7 +158,7 @@ func TestDontCreateObservationAfterRefreshTokenAndSignIn(t *testing.T) { observedPath[path] = struct{}{} h(w, r) } else { - require.NoError(t, fmt.Errorf("cannot observe the same resource twice")) + require.NoError(t, errors.New("cannot observe the same resource twice")) } }) if co == nil { @@ -320,6 +319,6 @@ func TestCertificateExpiration(t *testing.T) { // connection was closed by certificate expiration return case <-time.After(2 * duration): - require.NoError(t, fmt.Errorf("timeout")) + require.NoError(t, errors.New("timeout")) } } diff --git a/coap-gateway/service/signOff.go b/coap-gateway/service/signOff.go index b4f6409e8..7145b8512 100644 --- a/coap-gateway/service/signOff.go +++ b/coap-gateway/service/signOff.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "math" "net/url" @@ -74,13 +75,13 @@ func (s signOffData) updateSignOffDataFromAuthContext(client *session) signOffDa func (s signOffData) validateSignOffData() error { if s.deviceID == "" { - return fmt.Errorf("invalid device id") + return errors.New("invalid device id") } if s.userID == "" { - return fmt.Errorf("invalid user id") + return errors.New("invalid user id") } if s.accessToken == "" { - return fmt.Errorf("invalid access token") + return errors.New("invalid access token") } return nil } @@ -91,7 +92,7 @@ func getSignOffDataFromClaims(ctx context.Context, client *session, sod signOffD return "", err } - if err := jwtClaims.ValidateOwnerClaim(client.server.config.APIs.COAP.Authorization.OwnerClaim, sod.userID); err != nil { + if err = jwtClaims.ValidateOwnerClaim(client.server.config.APIs.COAP.Authorization.OwnerClaim, sod.userID); err != nil { return "", err } @@ -125,7 +126,7 @@ func signOffHandler(req *mux.Message, client *session) (*pool.Message, error) { err = client.blockSignOff.Acquire(ctx, math.MaxInt64) if err != nil { - return nil, statusErrorf(coapCodes.ServiceUnavailable, errFmtSignOff, fmt.Errorf("cannot acquire sign off lock: some commands are in progress")) + return nil, statusErrorf(coapCodes.ServiceUnavailable, errFmtSignOff, errors.New("cannot acquire sign off lock: some commands are in progress")) } defer client.blockSignOff.Release(math.MaxInt64) diff --git a/coap-gateway/service/signUp.go b/coap-gateway/service/signUp.go index d2a2c205f..a6c49f8f7 100644 --- a/coap-gateway/service/signUp.go +++ b/coap-gateway/service/signUp.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "github.com/plgd-dev/go-coap/v3/message" @@ -34,10 +35,10 @@ type CoapSignUpResponse struct { // Check that all required request fields are set func (request CoapSignUpRequest) checkOAuthRequest() error { if request.DeviceID == "" { - return fmt.Errorf("invalid device id") + return errors.New("invalid device id") } if request.AuthorizationCode == "" { - return fmt.Errorf("invalid authorization code") + return errors.New("invalid authorization code") } return nil } @@ -81,7 +82,7 @@ func getSignUpToken(ctx context.Context, client *session, signUp CoapSignUpReque return nil, statusErrorf(coapCodes.ServiceUnavailable, errFmtSignUP, err) } if token.RefreshToken == "" { - return nil, statusErrorf(coapCodes.Unauthorized, errFmtSignUP, fmt.Errorf("exchange didn't return a refresh token")) + return nil, statusErrorf(coapCodes.Unauthorized, errFmtSignUP, errors.New("exchange didn't return a refresh token")) } return token, nil } @@ -97,7 +98,7 @@ func getSignUpDataFromClaims(ctx context.Context, client *session, accessToken s return "", "", err } if owner == "" { - return "", "", fmt.Errorf("cannot determine owner") + return "", "", errors.New("cannot determine owner") } deviceID, err := client.server.VerifyAndResolveDeviceID(client.tlsDeviceID, signUp.DeviceID, claim) @@ -129,7 +130,7 @@ func signUpPostHandler(req *mux.Message, client *session) (*pool.Message, error) validUntil, ok := ValidUntil(token.Expiry) if !ok { - return nil, statusErrorf(coapCodes.Unauthorized, errFmtSignUP, fmt.Errorf("expired access token")) + return nil, statusErrorf(coapCodes.Unauthorized, errFmtSignUP, errors.New("expired access token")) } deviceID, owner, err := getSignUpDataFromClaims(req.Context(), client, token.AccessToken.String(), signUp) @@ -139,7 +140,7 @@ func signUpPostHandler(req *mux.Message, client *session) (*pool.Message, error) setDeviceIDToTracerSpan(req.Context(), deviceID) ctx := kitNetGrpc.CtxWithToken(req.Context(), token.AccessToken.String()) - if _, err := client.server.isClient.AddDevice(ctx, &pb.AddDeviceRequest{ + if _, err = client.server.isClient.AddDevice(ctx, &pb.AddDeviceRequest{ DeviceId: deviceID, }); err != nil { return nil, statusErrorf(coapconv.GrpcErr2CoapCode(err, coapconv.Update), errFmtSignUP, err) diff --git a/coap-gateway/service/utils_test.go b/coap-gateway/service/utils_test.go index 8aab65d32..eb7aad785 100644 --- a/coap-gateway/service/utils_test.go +++ b/coap-gateway/service/utils_test.go @@ -13,7 +13,6 @@ import ( "crypto/x509" "encoding/pem" "errors" - "fmt" "io" "os" "reflect" @@ -435,7 +434,7 @@ func testCoapDialWithHandler(t *testing.T, deviceID string, withTLS, identityCer InsecureSkipVerify: true, VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { if len(rawCerts) == 0 { - return fmt.Errorf("empty certificates chain") + return errors.New("empty certificates chain") } intermediateCAPool := x509.NewCertPool() certs := make([]*x509.Certificate, 0, len(rawCerts)) diff --git a/coap-gateway/uri/uri.go b/coap-gateway/uri/uri.go index 34e82e1f0..b198e124d 100644 --- a/coap-gateway/uri/uri.go +++ b/coap-gateway/uri/uri.go @@ -15,6 +15,8 @@ const ( ResourceDiscovery = Base + "/res" ResourceRoute = ApiV1 + "/devices" - InterfaceQueryKey = "if" - InterfaceQueryKeyPrefix = InterfaceQueryKey + "=" + InterfaceQueryKey = "if" + InterfaceQueryKeyPrefix = InterfaceQueryKey + "=" + ResourceTypeQueryKey = "rt" + ResourceTypeQueryKeyPrefix = ResourceTypeQueryKey + "=" ) diff --git a/dependency/googleapis b/dependency/googleapis index 29fdc0036..700240618 160000 --- a/dependency/googleapis +++ b/dependency/googleapis @@ -1 +1 @@ -Subproject commit 29fdc0036ce62452d188c5a246aa4664ef9cc4a3 +Subproject commit 7002406181eb300da880701035a25157a5099abb diff --git a/go.mod b/go.mod index 61995cfff..63c65499a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/plgd-dev/hub/v2 -go 1.21 +go 1.22 toolchain go1.22.0 @@ -9,112 +9,99 @@ require ( github.com/felixge/httpsnoop v1.0.4 github.com/fsnotify/fsnotify v1.7.0 github.com/fullstorydev/grpchan v1.1.1 - github.com/fxamacker/cbor/v2 v2.5.0 - github.com/go-co-op/gocron v1.37.0 + github.com/fxamacker/cbor/v2 v2.6.0 + github.com/go-co-op/gocron/v2 v2.3.0 github.com/gocql/gocql v1.6.0 - github.com/golang-jwt/jwt/v5 v5.2.0 + github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golang/snappy v0.0.4 github.com/google/go-querystring v1.1.0 - github.com/google/uuid v1.5.0 + github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.1 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 github.com/hashicorp/go-multierror v1.1.1 github.com/jessevdk/go-flags v1.5.0 github.com/json-iterator/go v1.1.12 github.com/jtacoma/uritemplates v1.0.0 github.com/karrick/tparse/v2 v2.8.2 - github.com/lestrrat-go/jwx/v2 v2.0.19 - github.com/nats-io/nats.go v1.31.0 - github.com/panjf2000/ants/v2 v2.9.0 - github.com/pion/dtls/v2 v2.2.8-0.20240102042511-9ffd96c827fe + github.com/lestrrat-go/jwx/v2 v2.0.21 + github.com/nats-io/nats.go v1.34.1 + github.com/panjf2000/ants/v2 v2.9.1 + github.com/pion/dtls/v2 v2.2.8-0.20240501061905-2c36d63320a0 github.com/pion/logging v0.2.2 - github.com/plgd-dev/device/v2 v2.2.5-0.20240112105119-e165727b7d41 - github.com/plgd-dev/go-coap/v3 v3.3.1 + github.com/plgd-dev/device/v2 v2.5.1-0.20240513064831-b553d1a87e1c + github.com/plgd-dev/go-coap/v3 v3.3.4 github.com/plgd-dev/kit/v2 v2.0.0-20211006190727-057b33161b90 github.com/pseudomuto/protoc-gen-doc v1.5.1 github.com/sirupsen/logrus v1.9.3 - github.com/stretchr/testify v1.8.4 - github.com/tidwall/gjson v1.17.0 + github.com/stretchr/testify v1.9.0 + github.com/tidwall/gjson v1.17.1 github.com/tidwall/sjson v1.2.5 github.com/ugorji/go/codec v1.2.12 github.com/vincent-petithory/dataurl v1.0.0 - go.mongodb.org/mongo-driver v1.13.1 - go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.46.1 - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 - go.opentelemetry.io/otel v1.21.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 - go.opentelemetry.io/otel/metric v1.21.0 - go.opentelemetry.io/otel/sdk v1.21.0 - go.opentelemetry.io/otel/trace v1.21.0 + github.com/web-of-things-open-source/thingdescription-go v0.0.0-20240510130416-741fef736e1e + go.mongodb.org/mongo-driver v1.15.0 + go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.49.0 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 + go.opentelemetry.io/otel v1.24.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 + go.opentelemetry.io/otel/metric v1.24.0 + go.opentelemetry.io/otel/sdk v1.24.0 + go.opentelemetry.io/otel/trace v1.24.0 go.uber.org/atomic v1.11.0 - go.uber.org/zap v1.26.0 - golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e - golang.org/x/net v0.21.0 - golang.org/x/oauth2 v0.16.0 - golang.org/x/sync v0.6.0 - google.golang.org/api v0.156.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 - google.golang.org/grpc v1.60.1 + go.uber.org/zap v1.27.0 + golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f + golang.org/x/net v0.24.0 + golang.org/x/oauth2 v0.19.0 + golang.org/x/sync v0.7.0 + google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6 + google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6 + google.golang.org/grpc v1.63.2 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 - google.golang.org/protobuf v1.32.0 + google.golang.org/protobuf v1.34.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - cloud.google.com/go/compute v1.23.3 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/compute v1.25.1 // indirect github.com/Masterminds/semver v1.4.2 // indirect github.com/Masterminds/sprig v2.15.0+incompatible // indirect - github.com/a8m/envsubst v1.4.2 // indirect - github.com/alecthomas/participle/v2 v2.1.1 // indirect github.com/aokoli/goutils v1.0.1 // indirect - github.com/bufbuild/protocompile v0.7.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/bufbuild/protocompile v0.13.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect - github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/dsnet/golib/memfile v1.0.0 // indirect - github.com/elliotchance/orderedmap v1.5.1 // indirect - github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect - github.com/fatih/color v1.16.0 // indirect + github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect + github.com/fredbi/uri v1.1.0 // indirect + github.com/go-json-experiment/json v0.0.0-20240418180308-af2d5061e6c2 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/goccy/go-yaml v1.11.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // 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/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/huandu/xstrings v1.0.0 // indirect github.com/imdario/mergo v0.3.4 // indirect - github.com/jhump/protoreflect v1.15.4 // indirect - github.com/jinzhu/copier v0.4.0 // indirect - github.com/klauspost/compress v1.17.4 // indirect + github.com/jhump/protoreflect v1.16.0 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect + github.com/klauspost/compress v1.17.8 // indirect github.com/lestrrat-go/blackmagic v1.0.2 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect - github.com/lestrrat-go/httprc v1.0.4 // indirect + github.com/lestrrat-go/httprc v1.0.5 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/option v1.0.1 // indirect - github.com/magiconair/properties v1.8.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mikefarah/yq/v4 v4.41.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.7.1 // indirect github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007 // indirect github.com/nats-io/nkeys v0.4.7 // indirect github.com/nats-io/nuid v1.0.1 // indirect - github.com/pelletier/go-toml/v2 v2.1.1 // indirect - github.com/pion/transport/v3 v3.0.1 // indirect + github.com/pion/transport/v3 v3.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pseudomuto/protokit v0.2.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect @@ -126,21 +113,28 @@ require ( github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect - github.com/yuin/gopher-lua v1.1.1 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect + go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.19.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect ) -// note: github.com/pion/dtls/v2/pkg/net package is not yet available in release branches -exclude github.com/pion/dtls/v2 v2.2.9 +replace ( + // note: github.com/pion/dtls/v2/pkg/net package is not yet available in release branches, + // so we force to the use of the pinned master branch + github.com/pion/dtls/v2 => github.com/pion/dtls/v2 v2.2.8-0.20240501061905-2c36d63320a0 + // later versions require go 1.22 + github.com/youmark/pkcs8 => github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a + // later versions require go 1.21 + go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo => go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.49.0 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc => go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 + go.opentelemetry.io/otel => go.opentelemetry.io/otel v1.24.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc => go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 + go.opentelemetry.io/otel/metric => go.opentelemetry.io/otel/metric v1.24.0 + go.opentelemetry.io/otel/sdk => go.opentelemetry.io/otel/sdk v1.24.0 + go.opentelemetry.io/otel/trace => go.opentelemetry.io/otel/trace v1.24.0 +) diff --git a/go.sum b/go.sum index 3c80433ef..01aafa37e 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,8 @@ 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/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 v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -9,10 +10,6 @@ github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITg github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/sprig v2.15.0+incompatible h1:0gSxPGWS9PAr7U2NsQ2YQg6juRDINkUyuvbb4b2Xm8w= github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/a8m/envsubst v1.4.2 h1:4yWIHXOLEJHQEFd4UjrWDrYeYlV7ncFWJOCBRLOZHQg= -github.com/a8m/envsubst v1.4.2/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY= -github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= -github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/aokoli/goutils v1.0.1 h1:7fpzNGoJ3VA8qcrm++XEE1QUe0mIwNeLa02Nwq7RDkg= github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -20,55 +17,53 @@ github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYE github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bufbuild/protocompile v0.7.1 h1:Kd8fb6EshOHXNNRtYAmLAwy/PotlyFoN0iMbuwGNh0M= -github.com/bufbuild/protocompile v0.7.1/go.mod h1:+Etjg4guZoAqzVk2czwEQP12yaxLJ8DxuqCJ9qHdH94= +github.com/bufbuild/protocompile v0.13.0 h1:6cwUB0Y2tSvmNxsbunwzmIto3xOlJOV7ALALuVOs92M= +github.com/bufbuild/protocompile v0.13.0/go.mod h1:dr++fGGeMPWHv7jPeT06ZKukm45NJscd7rUxQVzEKRk= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 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-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= -github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/dsnet/golib/memfile v0.0.0-20190531212259-571cdbcff553/go.mod h1:tXGNW9q3RwvWt1VV2qrRKlSSz0npnh12yftCSCy2T64= github.com/dsnet/golib/memfile v0.0.0-20200723050859-c110804dfa93/go.mod h1:tXGNW9q3RwvWt1VV2qrRKlSSz0npnh12yftCSCy2T64= github.com/dsnet/golib/memfile v1.0.0 h1:J9pUspY2bDCbF9o+YGwcf3uG6MdyITfh/Fk3/CaEiFs= github.com/dsnet/golib/memfile v1.0.0/go.mod h1:tXGNW9q3RwvWt1VV2qrRKlSSz0npnh12yftCSCy2T64= -github.com/elliotchance/orderedmap v1.5.1 h1:G1X4PYlljzimbdQ3RXmtIZiQ9d6aRQ3sH1nzjq5mECE= -github.com/elliotchance/orderedmap v1.5.1/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= 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.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/favadi/protoc-go-inject-tag v1.4.0 h1:K3KXxbgRw5WT4f43LbglARGz/8jVsDOS7uMjG4oNvXY= github.com/favadi/protoc-go-inject-tag v1.4.0/go.mod h1:AZ+PK+QDKUOLlBRG0rYiKkUX5Hw7+7GTFzlU99GFSbQ= +github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= +github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8= +github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fullstorydev/grpchan v1.1.1 h1:heQqIJlAv5Cnks9a70GRL2EJke6QQoUB25VGR6TZQas= github.com/fullstorydev/grpchan v1.1.1/go.mod h1:f4HpiV8V6htfY/K44GWV1ESQzHBTq7DinhzqQ95lpgc= github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= -github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA= +github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-acme/lego v2.7.2+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= -github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0= -github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY= +github.com/go-co-op/gocron/v2 v2.3.0 h1:UmXdUuql3h/+JN3rFDhZdDvgeCjR+r/zrSsQNZje8uo= +github.com/go-co-op/gocron/v2 v2.3.0/go.mod h1:ckPQw96ZuZLRUGu88vVpd9a6d9HakI14KWahFZtGvNw= +github.com/go-json-experiment/json v0.0.0-20240418180308-af2d5061e6c2 h1:lhCu2IkNoFfDdcjHos2ZtLdAsyxLZbkpijNzhvvM6BY= +github.com/go-json-experiment/json v0.0.0-20240418180308-af2d5061e6c2/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -83,8 +78,6 @@ github.com/go-ocf/kit v0.0.0-20200728130040-4aebdb6982bc/go.mod h1:TIsoMT/iB7t9P github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= -github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/gocql/gocql v1.6.0 h1:IdFdOTbnpbd0pDhl4REKQDM+Q0SzKXQ1Yh+YZZ8T/qU= github.com/gocql/gocql v1.6.0/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -92,12 +85,9 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= -github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -109,12 +99,9 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W 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.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.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 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= @@ -124,23 +111,18 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -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/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.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.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= @@ -149,10 +131,10 @@ github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZH github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1 h1:HcUWd006luQPljE73d5sk+/VgYPGUReEVz2y1/qylwY= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -171,10 +153,10 @@ github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSl github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E= -github.com/jhump/protoreflect v1.15.4 h1:mrwJhfQGGljwvR/jPEocli8KA6G9afbQpH8NY2wORcI= -github.com/jhump/protoreflect v1.15.4/go.mod h1:2B+zwrnMY3TTIqEK01OG/d3pyUycQBfDf+bx8fE2DNg= -github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= -github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg= +github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtacoma/uritemplates v1.0.0 h1:xwx5sBF7pPAb0Uj8lDC1Q/aBPpOFyQza7OC705ZlLCo= @@ -187,15 +169,13 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= -github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -204,71 +184,54 @@ github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= -github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8= -github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= +github.com/lestrrat-go/httprc v1.0.5 h1:bsTfiH8xaKOJPrg1R+E3iE/AWZr/x0Phj9PBTG/OLUk= +github.com/lestrrat-go/httprc v1.0.5/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/iter v0.0.0-20200422075355-fc1769541911/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= github.com/lestrrat-go/jwx v1.0.2/go.mod h1:TPF17WiSFegZo+c20fdpw49QD+/7n4/IsGvEmCSWwT0= -github.com/lestrrat-go/jwx/v2 v2.0.19 h1:ekv1qEZE6BVct89QA+pRF6+4pCpfVrOnEJnTnT4RXoY= -github.com/lestrrat-go/jwx/v2 v2.0.19/go.mod h1:l3im3coce1lL2cDeAjqmaR+Awx+X8Ih+2k8BuHNJ4CU= +github.com/lestrrat-go/jwx/v2 v2.0.21 h1:jAPKupy4uHgrHFEdjVjNkUgoBKtVDgrQPB/h55FHrR0= +github.com/lestrrat-go/jwx/v2 v2.0.21/go.mod h1:09mLW8zto6bWL9GbwnqAli+ArLf+5M33QLQPDggkUWM= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/pdebug v0.0.0-20200204225717-4d6bd78da58d/go.mod h1:B06CSso/AWxiPejj+fheUINGeBKeeEZNt8w+EoU7+L8= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/mikefarah/yq/v4 v4.41.1 h1:HIyr+VCctIpiMl/mhplQJkzvsFeEVv7AurigXeX4cuI= -github.com/mikefarah/yq/v4 v4.41.1/go.mod h1:Qpwgwtmrn3XBeeACw0z8brRNBijX8Lw2RIiJFmS0+uE= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007 h1:28i1IjGcx8AofiB4N3q5Yls55VEaitzuEPkFJEVgGkA= github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= -github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E= -github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8= +github.com/nats-io/nats.go v1.34.1 h1:syWey5xaNHZgicYBemv0nohUPPmaLteiBEUT6Q5+F/4= +github.com/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/panjf2000/ants/v2 v2.4.3/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= -github.com/panjf2000/ants/v2 v2.9.0 h1:SztCLkVxBRigbg+vt0S5QvF5vxAbxbKt09/YfAJ0tEo= -github.com/panjf2000/ants/v2 v2.9.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I= +github.com/panjf2000/ants/v2 v2.9.1 h1:Q5vh5xohbsZXGcD6hhszzGqB7jSSc2/CRr3QKIga8Kw= +github.com/panjf2000/ants/v2 v2.9.1/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= -github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/pion/dtls/v2 v2.0.1-0.20200503085337-8e86b3a7d585/go.mod h1:/GahSOC8ZY/+17zkaGJIG4OUkSGAcZu/N/g3roBOCkM= -github.com/pion/dtls/v2 v2.0.10-0.20210502094952-3dc563b9aede/go.mod h1:86wv5dgx2J/z871nUR+5fTTY9tISLUlo+C5Gm86r1Hs= -github.com/pion/dtls/v2 v2.2.8-0.20240102042511-9ffd96c827fe h1:irKb6v72GiA86l+Tp0UZjSZqiOj8LwFxBDvzkhmoO/w= -github.com/pion/dtls/v2 v2.2.8-0.20240102042511-9ffd96c827fe/go.mod h1:eWsePf7yhHNQGu6UKU6xs2XMUYpHX2uqqvyZhNB6ooA= +github.com/pion/dtls/v2 v2.2.8-0.20240501061905-2c36d63320a0 h1:050ahk2K4HqwxPi2YM6Yc4lIttwNSY2+n9xPVsS3zoQ= +github.com/pion/dtls/v2 v2.2.8-0.20240501061905-2c36d63320a0/go.mod h1:tjBBbkwKGSQQZl36HQa2va5HqR9rWhujhlJMrgE2b/o= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE= -github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q= -github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A= -github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= -github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= -github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4= +github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/plgd-dev/device/v2 v2.2.5-0.20240112105119-e165727b7d41 h1:1oTDtgAjVkeOX63MzvdiB/kx2RS1UYOtQMs6ywNejvA= -github.com/plgd-dev/device/v2 v2.2.5-0.20240112105119-e165727b7d41/go.mod h1:US5p507VILktZa6Ep77gTEqwY8F+IbVUmtbt5aTtdlI= +github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= +github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= +github.com/plgd-dev/device/v2 v2.5.1-0.20240513064831-b553d1a87e1c h1:kNF2KvyCzA8IMERdHUrL/LMdsuZM/tXGjLVzEX2lcg4= +github.com/plgd-dev/device/v2 v2.5.1-0.20240513064831-b553d1a87e1c/go.mod h1:2mFPs55x2Li76zkrHdRNY3yOqVWSh59hiUw+6FYXA0k= github.com/plgd-dev/go-coap/v2 v2.0.4-0.20200819112225-8eb712b901bc/go.mod h1:+tCi9Q78H/orWRtpVWyBgrr4vKFo2zYtbbxUllerBp4= github.com/plgd-dev/go-coap/v2 v2.4.1-0.20210517130748-95c37ac8e1fa/go.mod h1:rA7fc7ar+B/qa+Q0hRqv7yj/EMtIlmo1l7vkQGSrHPU= -github.com/plgd-dev/go-coap/v3 v3.3.1 h1:oxVnn5MAOEWImoGgoG5S0grTXQXqhNu5gQqW7zMPu40= -github.com/plgd-dev/go-coap/v3 v3.3.1/go.mod h1:r3KbxxpBgOPmC0fh6y0yUrDvJh3LdCrhD2zdRr0L1j4= +github.com/plgd-dev/go-coap/v3 v3.3.4 h1:clDLFOXXmXfhZqB0eSk6WJs2iYfjC2J22Ixwu5MHiO0= +github.com/plgd-dev/go-coap/v3 v3.3.4/go.mod h1:vxBvAgXxL+Au/58XYTM+8ftqO/ycFC9/Dh+uI72xYjA= github.com/plgd-dev/kit v0.0.0-20200819113605-d5fcf3e94f63/go.mod h1:Yl9zisyXfPdtP9hTWlJqjJYXmgU/jtSDKttz9/CeD90= github.com/plgd-dev/kit/v2 v2.0.0-20211006190727-057b33161b90 h1:TC1HJ/UbyflJFPvaOdGmNZ5TeFGex1/dyr9urNGLy7M= github.com/plgd-dev/kit/v2 v2.0.0-20211006190727-057b33161b90/go.mod h1:Z7oKFLSGQjdi8eInxwFCs0tSApuEM1o0qNck+sJYp4M= @@ -282,9 +245,8 @@ github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3 github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -294,6 +256,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 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= @@ -302,13 +265,13 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= -github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= +github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= @@ -325,6 +288,8 @@ github.com/valyala/fasthttp v1.12.0/go.mod h1:229t1eWu9UXTPmoUkbpN/fctKPBY4IJoFX github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vincent-petithory/dataurl v1.0.0 h1:cXw+kPto8NLuJtlMsI152irrVw9fRDX8AbShPRpg2CI= github.com/vincent-petithory/dataurl v1.0.0/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9CvnvxyvZy6I1MrG/U= +github.com/web-of-things-open-source/thingdescription-go v0.0.0-20240510130416-741fef736e1e h1:blQyU8WqqyRcBmaAPLiU5cTg9BSQu04CJZ/ffEzgI1s= +github.com/web-of-things-open-source/thingdescription-go v0.0.0-20240510130416-741fef736e1e/go.mod h1:L/jWuWf+v7rmuFykpUP/runRXTnnA0QdGGgou8vzPrw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= @@ -333,46 +298,41 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= -github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= -go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= -go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.46.1 h1:C6OqX3inTcc1vUX2BL7Au7cQO20/0fCI02XdInR8m5Y= -go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.46.1/go.mod h1:M9ZtzJcGI4ejexSjUP69JmhbzAe93mu2xUBH3QBUtLM= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= -go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc= +go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= +go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.49.0 h1:qF3LdpkD3Kbaw0Smsh+SVcJI/mtYGz9ZdCmu0YF2Lo4= +go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.49.0/go.mod h1:eqNF9g7W06ubrU7jk6M6UW9OTrcSPZvVY10cw9DUJ7c= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= +go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -382,28 +342,23 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e h1:723BNChdd0c2Wk6WOE320qGBiPtYx0F0Bbm1kriShfE= -golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -428,25 +383,19 @@ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/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-20201021035429-f5854403a974/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-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -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-20210502030024-e5908800b52b/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 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.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= 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= @@ -456,8 +405,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -474,22 +423,19 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -498,7 +444,6 @@ 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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -523,34 +468,25 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.156.0 h1:yloYcGbBtVYjLKQe4enCunxvwn3s2w/XPrrhVf6MsvQ= -google.golang.org/api v0.156.0/go.mod h1:bUSmn4KFO0Q+69zo9CNIDp4Psi6BqM0np0CbzKRSiSY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= -google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 h1:OPXtXn7fNMaXwO3JvOmF1QyTc00jsSFFz1vXXBOdCDo= -google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6 h1:DTJM0R8LECCgFeUwApvcEJHz85HLagW8uRENYxHh1ww= +google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6 h1:DujSIu+2tC9Ht0aPNA7jgj23Iq8Ewi5sgkQ++wdvonE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -564,8 +500,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD 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.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4= +google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -574,8 +510,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE= -gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/grpc-gateway/client/client.go b/grpc-gateway/client/client.go index d4959d88f..c049e8255 100644 --- a/grpc-gateway/client/client.go +++ b/grpc-gateway/client/client.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "crypto/x509" + "errors" "fmt" "sync" "time" @@ -44,7 +45,7 @@ func New(client pb.GrpcGatewayClient) *Client { // NewFromConfig constructs a new client client. For every call there is expected jwt token for grpc stored in context. func NewFromConfig(cfg *Config, tlsCfg *tls.Config) (*Client, error) { if cfg == nil || cfg.GatewayAddress == "" { - return nil, fmt.Errorf("missing client client config") + return nil, errors.New("missing client config") } keepAlive := keepalive.ClientParameters{ @@ -52,7 +53,7 @@ func NewFromConfig(cfg *Config, tlsCfg *tls.Config) (*Client, error) { PermitWithoutStream: true, } - conn, err := grpc.Dial(cfg.GatewayAddress, grpc.WithKeepaliveParams(keepAlive), grpc.WithTransportCredentials(credentials.NewTLS(tlsCfg))) + conn, err := grpc.NewClient(cfg.GatewayAddress, grpc.WithKeepaliveParams(keepAlive), grpc.WithTransportCredentials(credentials.NewTLS(tlsCfg))) if err != nil { return nil, fmt.Errorf("cannot create certificate authority client: %w", err) } @@ -194,19 +195,20 @@ func (c *Client) GetResourceLinksIterator(ctx context.Context, deviceIDs []strin // GetResourcesIterator gets resources contents from resource twin (cache of backend). JWT token must be stored in context for grpc call. // By resourceIDs you can specify resources by deviceID and Href which will be retrieved from the backend, nil means all resources. // Or by deviceIDs or resourceTypes you can filter output when you get all resources. -// Eg: +// +// Example: // // get all resources // it := client.GetResourcesIterator(ctx, nil, nil) // // get all oic.wk.d resources -// iter := client.GetResourcesIterator(ctx, nil, nil, "oic.wk.d") +// it := client.GetResourcesIterator(ctx, nil, nil, "oic.wk.d") // // get oic.wk.d resources of 2 devices -// iter := client.GetResourcesIterator(ctx, nil, string["60f6869d-343a-4989-7462-81ef215d31af", "07ef9eb6-1ce9-4ce4-73a6-9ee0a1d534d2"], "oic.wk.d") +// it := client.GetResourcesIterator(ctx, nil, string["60f6869d-343a-4989-7462-81ef215d31af", "07ef9eb6-1ce9-4ce4-73a6-9ee0a1d534d2"], "oic.wk.d") // // get a certain resource /oic/p of the device"60f6869d-343a-4989-7462-81ef215d31af" -// iter := client.GetResourcesIterator(ctx, commands.NewResourceID("60f6869d-343a-4989-7462-81ef215d31af", /oic/p), nil) +// it := client.GetResourcesIterator(ctx, commands.NewResourceID("60f6869d-343a-4989-7462-81ef215d31af", /oic/p), nil) // // Next queries the next resource value. // Returns false when failed or having no more items. diff --git a/grpc-gateway/client/client_test.go b/grpc-gateway/client/client_test.go index b487e5c38..94555f8c9 100644 --- a/grpc-gateway/client/client_test.go +++ b/grpc-gateway/client/client_test.go @@ -111,9 +111,6 @@ func (h *gatewayHandler) GetResources(_ *pb.GetResourcesRequest, srv pb.GrpcGate if err != nil { return err } - if err != nil { - return err - } return nil } diff --git a/grpc-gateway/client/createResource_test.go b/grpc-gateway/client/createResource_test.go index 28c4b0c97..aad482a4c 100644 --- a/grpc-gateway/client/createResource_test.go +++ b/grpc-gateway/client/createResource_test.go @@ -70,17 +70,17 @@ func TestClient_CreateResource(t *testing.T) { c := NewTestClient(t) defer func() { err := c.Close() - assert.NoError(t, err) + require.NoError(t, err) }() _, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) defer shutdownDevSim() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + runctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() var got interface{} - err := c.CreateResource(ctx, tt.args.deviceID, tt.args.href, tt.args.data, &got) + err := c.CreateResource(runctx, tt.args.deviceID, tt.args.href, tt.args.data, &got) if tt.wantErr { require.Error(t, err) var grpcStatus interface { diff --git a/grpc-gateway/client/deleteResource_test.go b/grpc-gateway/client/deleteResource_test.go index 501bb2d65..9dbc20918 100644 --- a/grpc-gateway/client/deleteResource_test.go +++ b/grpc-gateway/client/deleteResource_test.go @@ -15,7 +15,6 @@ import ( "github.com/plgd-dev/hub/v2/test/config" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" "github.com/plgd-dev/hub/v2/test/service" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -87,7 +86,7 @@ func TestClientDeleteResource(t *testing.T) { c := NewTestClient(t) defer func() { err := c.Close() - assert.NoError(t, err) + require.NoError(t, err) }() _, shutdownDevsim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) defer shutdownDevsim() @@ -95,10 +94,10 @@ func TestClientDeleteResource(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + runctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() var got interface{} - err := c.DeleteResource(ctx, tt.args.deviceID, tt.args.href, &got) + err := c.DeleteResource(runctx, tt.args.deviceID, tt.args.href, &got) if tt.wantErr { require.Error(t, err) return @@ -176,7 +175,7 @@ func TestClientBatchDeleteResource(t *testing.T) { c := NewTestClient(t) defer func() { err := c.Close() - assert.NoError(t, err) + require.NoError(t, err) }() _, shutdown := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) defer shutdown() @@ -184,10 +183,10 @@ func TestClientBatchDeleteResource(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + runctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() var got test.CollectionLinkRepresentations - err := c.DeleteResource(ctx, tt.args.deviceID, tt.args.href, &got, client.WithInterface(interfaces.OC_IF_B)) + err := c.DeleteResource(runctx, tt.args.deviceID, tt.args.href, &got, client.WithInterface(interfaces.OC_IF_B)) if tt.wantErr { require.Error(t, err) require.Equal(t, tt.wantErrCode, status.Convert(err).Code()) diff --git a/grpc-gateway/client/deviceSubscriber.go b/grpc-gateway/client/deviceSubscriber.go index e4daefa5e..23e76688a 100644 --- a/grpc-gateway/client/deviceSubscriber.go +++ b/grpc-gateway/client/deviceSubscriber.go @@ -322,7 +322,7 @@ func (s *DeviceSubscriber) createSpanEvent(ctx context.Context, name string) (co opentelemetry.InstrumentationName, trace.WithInstrumentationVersion(opentelemetry.SemVersion()), ) - return tracer.Start(ctx, name, trace.WithSpanKind(trace.SpanKindConsumer)) + return tracer.Start(ctx, name, trace.WithSpanKind(trace.SpanKindConsumer)) //nolint:spancheck } func (s *DeviceSubscriber) processPendingCommand(ctx context.Context, h *DeviceSubscriptionHandlers, ev *pbGRPC.PendingCommand) error { diff --git a/grpc-gateway/client/deviceSubscriptions.go b/grpc-gateway/client/deviceSubscriptions.go index 6ce78045e..e1579ae94 100644 --- a/grpc-gateway/client/deviceSubscriptions.go +++ b/grpc-gateway/client/deviceSubscriptions.go @@ -114,7 +114,7 @@ func (s *DeviceSubscriptions) doOp(ctx context.Context, req *pb.SubscribeToEvent return nil, fmt.Errorf("unexpected event %+v", ev) } if op.GetErrorStatus().GetCode() != pb.Event_OperationProcessed_ErrorStatus_OK { - return nil, fmt.Errorf(op.GetErrorStatus().GetMessage()) + return nil, errors.New(op.GetErrorStatus().GetMessage()) } return ev, nil } @@ -146,70 +146,70 @@ type deviceSub struct { func (s *deviceSub) HandleResourcePublished(ctx context.Context, val *events.ResourceLinksPublished) error { if s.ResourcePublishedHandler == nil { - return fmt.Errorf("ResourcePublishedHandler in not supported") + return errors.New("ResourcePublishedHandler in not supported") } return s.ResourcePublishedHandler.HandleResourcePublished(ctx, val) } func (s *deviceSub) HandleResourceUnpublished(ctx context.Context, val *events.ResourceLinksUnpublished) error { if s.ResourceUnpublishedHandler == nil { - return fmt.Errorf("ResourceUnpublishedHandler in not supported") + return errors.New("ResourceUnpublishedHandler in not supported") } return s.ResourceUnpublishedHandler.HandleResourceUnpublished(ctx, val) } func (s *deviceSub) HandleResourceUpdatePending(ctx context.Context, val *events.ResourceUpdatePending) error { if s.ResourceUpdatePendingHandler == nil { - return fmt.Errorf("ResourceUpdatePendingHandler in not supported") + return errors.New("ResourceUpdatePendingHandler in not supported") } return s.ResourceUpdatePendingHandler.HandleResourceUpdatePending(ctx, val) } func (s *deviceSub) HandleResourceUpdated(ctx context.Context, val *events.ResourceUpdated) error { if s.ResourceUpdatedHandler == nil { - return fmt.Errorf("ResourceUpdatedHandler in not supported") + return errors.New("ResourceUpdatedHandler in not supported") } return s.ResourceUpdatedHandler.HandleResourceUpdated(ctx, val) } func (s *deviceSub) HandleResourceRetrievePending(ctx context.Context, val *events.ResourceRetrievePending) error { if s.ResourceRetrievePendingHandler == nil { - return fmt.Errorf("ResourceRetrievePendingHandler in not supported") + return errors.New("ResourceRetrievePendingHandler in not supported") } return s.ResourceRetrievePendingHandler.HandleResourceRetrievePending(ctx, val) } func (s *deviceSub) HandleResourceRetrieved(ctx context.Context, val *events.ResourceRetrieved) error { if s.ResourceRetrievedHandler == nil { - return fmt.Errorf("ResourceRetrievedHandler in not supported") + return errors.New("ResourceRetrievedHandler in not supported") } return s.ResourceRetrievedHandler.HandleResourceRetrieved(ctx, val) } func (s *deviceSub) HandleResourceDeletePending(ctx context.Context, val *events.ResourceDeletePending) error { if s.ResourceDeletePendingHandler == nil { - return fmt.Errorf("ResourceDeletePendingHandler in not supported") + return errors.New("ResourceDeletePendingHandler in not supported") } return s.ResourceDeletePendingHandler.HandleResourceDeletePending(ctx, val) } func (s *deviceSub) HandleResourceDeleted(ctx context.Context, val *events.ResourceDeleted) error { if s.ResourceDeletedHandler == nil { - return fmt.Errorf("ResourceDeletedHandler in not supported") + return errors.New("ResourceDeletedHandler in not supported") } return s.ResourceDeletedHandler.HandleResourceDeleted(ctx, val) } func (s *deviceSub) HandleResourceCreatePending(ctx context.Context, val *events.ResourceCreatePending) error { if s.ResourceCreatePendingHandler == nil { - return fmt.Errorf("ResourceCreatePendingHandler in not supported") + return errors.New("ResourceCreatePendingHandler in not supported") } return s.ResourceCreatePendingHandler.HandleResourceCreatePending(ctx, val) } func (s *deviceSub) HandleResourceCreated(ctx context.Context, val *events.ResourceCreated) error { if s.ResourceCreatedHandler == nil { - return fmt.Errorf("ResourceCreatedHandler in not supported") + return errors.New("ResourceCreatedHandler in not supported") } return s.ResourceCreatedHandler.HandleResourceCreated(ctx, val) } @@ -229,7 +229,7 @@ func (s *Subcription) Cancel(ctx context.Context) error { func getSubscribeTypeAndHandler(closeErrorHandler SubscriptionHandler, handle interface{}) ([]pb.SubscribeToEvents_CreateSubscription_Event, *deviceSub, error) { if closeErrorHandler == nil { - return nil, nil, fmt.Errorf("invalid closeErrorHandler") + return nil, nil, errors.New("invalid closeErrorHandler") } var resourcePublishedHandler ResourcePublishedHandler var resourceUnpublishedHandler ResourceUnpublishedHandler @@ -285,7 +285,7 @@ func getSubscribeTypeAndHandler(closeErrorHandler SubscriptionHandler, handle in } if len(filterEvents) == 0 { - return nil, nil, fmt.Errorf("invalid handler - supported handlers: ResourcePublishedHandler, ResourceUnpublishedHandler, ResourceUpdatePendingHandler, ResourceUpdatedHandler, ResourceRetrievePendingHandler, ResourceRetrievedHandler, ResourceDeletePendingHandler, ResourceDeletedHandler, ResourceCreatePendingHandler, ResourceCreatedHandler") + return nil, nil, errors.New("invalid handler - supported handlers: ResourcePublishedHandler, ResourceUnpublishedHandler, ResourceUpdatePendingHandler, ResourceUpdatedHandler, ResourceRetrievePendingHandler, ResourceRetrievedHandler, ResourceDeletePendingHandler, ResourceDeletedHandler, ResourceCreatePendingHandler, ResourceCreatedHandler") } return filterEvents, &deviceSub{ @@ -306,7 +306,7 @@ func getSubscribeTypeAndHandler(closeErrorHandler SubscriptionHandler, handle in func (s *DeviceSubscriptions) Subscribe(ctx context.Context, deviceID string, closeErrorHandler SubscriptionHandler, handle interface{}) (*Subcription, error) { token, err := uuid.NewRandom() if err != nil { - return nil, fmt.Errorf("cannot generate token for subscribe") + return nil, errors.New("cannot generate token for subscribe") } filterEvents, eh, err := getSubscribeTypeAndHandler(closeErrorHandler, handle) @@ -336,7 +336,7 @@ func (s *DeviceSubscriptions) Subscribe(ctx context.Context, deviceID string, cl } cancelToken, err := uuid.NewRandom() if err != nil { - return fmt.Errorf("cannot generate token for cancellation") + return errors.New("cannot generate token for cancellation") } _, err = s.doOp(ctx, &pb.SubscribeToEvents{ Action: &pb.SubscribeToEvents_CancelSubscription_{ @@ -437,7 +437,7 @@ func (s *DeviceSubscriptions) handleSubscriptionCanceled(e *pb.Event) (processed ha.OnClose() return true } - ha.Error(fmt.Errorf(reason)) + ha.Error(errors.New(reason)) return true } diff --git a/grpc-gateway/client/deviceSubscriptions_test.go b/grpc-gateway/client/deviceSubscriptions_test.go index def1d9155..15d19b7a3 100644 --- a/grpc-gateway/client/deviceSubscriptions_test.go +++ b/grpc-gateway/client/deviceSubscriptions_test.go @@ -23,7 +23,6 @@ import ( pbTest "github.com/plgd-dev/hub/v2/test/pb" "github.com/plgd-dev/hub/v2/test/service" "github.com/plgd-dev/kit/v2/codec/cbor" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace/noop" ) @@ -85,8 +84,8 @@ func TestObserveDeviceResourcesRetrieve(t *testing.T) { c := NewTestClient(t) defer func() { - err := c.Close() - assert.NoError(t, err) + errC := c.Close() + require.NoError(t, errC) }() deviceID, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) defer shutdownDevSim() @@ -95,8 +94,8 @@ func TestObserveDeviceResourcesRetrieve(t *testing.T) { sub, err := c.NewDeviceSubscription(ctx, deviceID, h) require.NoError(t, err) defer func() { - wait, err := sub.Cancel() - require.NoError(t, err) + wait, errC := sub.Cancel() + require.NoError(t, errC) wait() }() @@ -115,14 +114,14 @@ func TestObserveDeviceResourcesRetrieve(t *testing.T) { SubscriptionId: sub.ID(), CorrelationId: retrieveCorrelationID, Type: &pb.Event_ResourceRetrievePending{ - ResourceRetrievePending: pbTest.MakeResourceRetrievePending(deviceID, platform.ResourceURI, retrieveCorrelationID), + ResourceRetrievePending: pbTest.MakeResourceRetrievePending(deviceID, platform.ResourceURI, []string{platform.ResourceType}, retrieveCorrelationID), }, }, { SubscriptionId: sub.ID(), CorrelationId: retrieveCorrelationID, Type: &pb.Event_ResourceRetrieved{ - ResourceRetrieved: pbTest.MakeResourceRetrieved(t, deviceID, platform.ResourceURI, retrieveCorrelationID, + ResourceRetrieved: pbTest.MakeResourceRetrieved(t, deviceID, platform.ResourceURI, []string{platform.ResourceType}, retrieveCorrelationID, map[string]interface{}{ "mnmn": "ocfcloud.com", "x.org.iotivity.version": test.GetIotivityLiteVersion(t, deviceID), @@ -180,8 +179,8 @@ func TestObserveDeviceResourcesUpdate(t *testing.T) { c := NewTestClient(t) defer func() { - err := c.Close() - assert.NoError(t, err) + errC := c.Close() + require.NoError(t, errC) }() deviceID, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) defer shutdownDevSim() @@ -193,8 +192,8 @@ func TestObserveDeviceResourcesUpdate(t *testing.T) { sub, err := c.NewDeviceSubscription(ctx, deviceID, h) require.NoError(t, err) defer func() { - wait, err := sub.Cancel() - require.NoError(t, err) + wait, errC := sub.Cancel() + require.NoError(t, errC) wait() }() @@ -208,8 +207,8 @@ func TestObserveDeviceResourcesUpdate(t *testing.T) { v := map[string]interface{}{ "value": true, } - d, err := cbor.Encode(v) - require.NoError(t, err) + d, errEnc := cbor.Encode(v) + require.NoError(t, errEnc) return d }(), }, @@ -225,7 +224,7 @@ func TestObserveDeviceResourcesUpdate(t *testing.T) { SubscriptionId: sub.ID(), CorrelationId: updCorrelationID, Type: &pb.Event_ResourceUpdatePending{ - ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), updCorrelationID, + ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), test.TestResourceSwitchesInstanceResourceTypes, updCorrelationID, map[string]interface{}{ "value": true, }), @@ -253,7 +252,8 @@ func TestObserveDeviceResourcesUpdate(t *testing.T) { return d }(), }, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, updCorrelationID, oauthService.DeviceUserID), + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, updCorrelationID, oauthService.DeviceUserID), + ResourceTypes: test.TestResourceSwitchesInstanceResourceTypes, }, }, }, @@ -308,8 +308,8 @@ func TestObserveDeviceResourcesCreateAndDelete(t *testing.T) { c := NewTestClient(t) defer func() { - err := c.Close() - assert.NoError(t, err) + errC := c.Close() + require.NoError(t, errC) }() deviceID, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) defer shutdownDevSim() @@ -318,8 +318,8 @@ func TestObserveDeviceResourcesCreateAndDelete(t *testing.T) { sub, err := c.NewDeviceSubscription(ctx, deviceID, h) require.NoError(t, err) defer func() { - wait, err := sub.Cancel() - require.NoError(t, err) + wait, errC := sub.Cancel() + require.NoError(t, errC) wait() }() @@ -345,7 +345,7 @@ func TestObserveDeviceResourcesCreateAndDelete(t *testing.T) { SubscriptionId: sub.ID(), CorrelationId: createCorrelationID, Type: &pb.Event_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, test.TestResourceSwitchesHref, createCorrelationID, + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, createCorrelationID, test.MakeSwitchResourceDefaultData()), }, }, @@ -353,7 +353,7 @@ func TestObserveDeviceResourcesCreateAndDelete(t *testing.T) { SubscriptionId: sub.ID(), CorrelationId: createCorrelationID, Type: &pb.Event_ResourceCreated{ - ResourceCreated: pbTest.MakeResourceCreated(t, deviceID, test.TestResourceSwitchesHref, createCorrelationID, + ResourceCreated: pbTest.MakeResourceCreated(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, createCorrelationID, pbTest.MakeCreateSwitchResourceResponseData(switchID)), }, }, @@ -383,7 +383,7 @@ func TestObserveDeviceResourcesCreateAndDelete(t *testing.T) { SubscriptionId: sub.ID(), CorrelationId: delCorrelationID, Type: &pb.Event_ResourceDeletePending{ - ResourceDeletePending: pbTest.MakeResourceDeletePending(deviceID, test.TestResourceSwitchesInstanceHref(switchID), + ResourceDeletePending: pbTest.MakeResourceDeletePending(deviceID, test.TestResourceSwitchesInstanceHref(switchID), test.TestResourceSwitchesInstanceResourceTypes, delCorrelationID), }, }, @@ -391,7 +391,7 @@ func TestObserveDeviceResourcesCreateAndDelete(t *testing.T) { SubscriptionId: sub.ID(), CorrelationId: delCorrelationID, Type: &pb.Event_ResourceDeleted{ - ResourceDeleted: pbTest.MakeResourceDeleted(deviceID, test.TestResourceSwitchesInstanceHref(switchID), + ResourceDeleted: pbTest.MakeResourceDeleted(deviceID, test.TestResourceSwitchesInstanceHref(switchID), test.TestResourceSwitchesInstanceResourceTypes, delCorrelationID), }, }, diff --git a/grpc-gateway/client/devicesSubscription.go b/grpc-gateway/client/devicesSubscription.go index 5106cab38..2a02cfdec 100644 --- a/grpc-gateway/client/devicesSubscription.go +++ b/grpc-gateway/client/devicesSubscription.go @@ -69,7 +69,7 @@ func NewDevicesSubscription(ctx context.Context, closeErrorHandler SubscriptionH } if deviceMetadataUpdatedHandler == nil && deviceRegisteredHandler == nil && deviceUnregisteredHandler == nil { - return nil, fmt.Errorf("invalid handler - it's supports: DeviceMetadataUpdatedHandler, DeviceRegisteredHandler, DeviceUnregisteredHandler") + return nil, errors.New("invalid handler - it's supports: DeviceMetadataUpdatedHandler, DeviceRegisteredHandler, DeviceUnregisteredHandler") } client, err := New(gwClient).SubscribeToEventsWithCurrentState(ctx, time.Minute) if err != nil { @@ -95,7 +95,7 @@ func NewDevicesSubscription(ctx context.Context, closeErrorHandler SubscriptionH return nil, fmt.Errorf("unexpected event %+v", ev) } if op.GetErrorStatus().GetCode() != pb.Event_OperationProcessed_ErrorStatus_OK { - return nil, fmt.Errorf(op.GetErrorStatus().GetMessage()) + return nil, errors.New(op.GetErrorStatus().GetMessage()) } var wg sync.WaitGroup @@ -169,7 +169,7 @@ func (s *DevicesSubscription) handleCancel(cancel *pb.Event_SubscriptionCanceled s.closeErrorHandler.OnClose() return } - s.closeErrorHandler.Error(fmt.Errorf(reason)) + s.closeErrorHandler.Error(errors.New(reason)) } func (s *DevicesSubscription) runRecv() { diff --git a/grpc-gateway/client/generalMessageCodec.go b/grpc-gateway/client/generalMessageCodec.go index 3d32eda06..d83db6c64 100644 --- a/grpc-gateway/client/generalMessageCodec.go +++ b/grpc-gateway/client/generalMessageCodec.go @@ -1,6 +1,7 @@ package client import ( + "errors" "fmt" "io" @@ -55,7 +56,7 @@ func (GeneralMessageCodec) Decode(m *pool.Message, v interface{}) error { } if m.Body() == nil { - return fmt.Errorf("unexpected empty body") + return errors.New("unexpected empty body") } if err := decoder(m.Body(), v); err != nil { diff --git a/grpc-gateway/client/getDevice_test.go b/grpc-gateway/client/getDevice_test.go index d47cbc4b1..525d5f517 100644 --- a/grpc-gateway/client/getDevice_test.go +++ b/grpc-gateway/client/getDevice_test.go @@ -16,7 +16,6 @@ import ( "github.com/plgd-dev/hub/v2/test/config" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" "github.com/plgd-dev/hub/v2/test/service" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -96,7 +95,7 @@ func TestClient_GetDevice(t *testing.T) { c := NewTestClient(t) defer func() { err := c.Close() - assert.NoError(t, err) + require.NoError(t, err) }() _, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) @@ -104,9 +103,9 @@ func TestClient_GetDevice(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + runctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - got, err := c.GetDevice(ctx, tt.args.deviceID) + got, err := c.GetDevice(runctx, tt.args.deviceID) if tt.wantErr { require.Error(t, err) return @@ -117,6 +116,7 @@ func TestClient_GetDevice(t *testing.T) { got.Device.ProtocolIndependentId = "" got.Device.Metadata.Connection.Id = "" got.Device.Metadata.Connection.ConnectedAt = 0 + got.Device.Metadata.Connection.LocalEndpoints = nil got.Device.Metadata.Connection.ServiceId = "" got.Device.Metadata.TwinSynchronization.SyncingAt = 0 got.Device.Metadata.TwinSynchronization.InSyncAt = 0 diff --git a/grpc-gateway/client/getDevices_test.go b/grpc-gateway/client/getDevices_test.go index 289cd9c65..e92774ab1 100644 --- a/grpc-gateway/client/getDevices_test.go +++ b/grpc-gateway/client/getDevices_test.go @@ -11,7 +11,6 @@ import ( "github.com/plgd-dev/hub/v2/test/config" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" "github.com/plgd-dev/hub/v2/test/service" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -21,6 +20,7 @@ func sortDevices(s map[string]*client.DeviceDetails) map[string]*client.DeviceDe x.Device.ProtocolIndependentId = "" x.Device.Metadata.Connection.Id = "" x.Device.Metadata.Connection.ConnectedAt = 0 + x.Device.Metadata.Connection.LocalEndpoints = nil x.Device.Metadata.Connection.ServiceId = "" x.Device.Metadata.TwinSynchronization.SyncingAt = 0 x.Device.Metadata.TwinSynchronization.InSyncAt = 0 @@ -72,7 +72,7 @@ func TestClient_GetDevices(t *testing.T) { c := NewTestClient(t) defer func() { err := c.Close() - assert.NoError(t, err) + require.NoError(t, err) }() _, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) @@ -80,9 +80,9 @@ func TestClient_GetDevices(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + runctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - got, err := c.GetDevices(ctx, tt.args.opts...) + got, err := c.GetDevices(runctx, tt.args.opts...) if tt.wantErr { require.Error(t, err) return diff --git a/grpc-gateway/client/getResource_test.go b/grpc-gateway/client/getResource_test.go index b72f10e88..6131789f8 100644 --- a/grpc-gateway/client/getResource_test.go +++ b/grpc-gateway/client/getResource_test.go @@ -13,7 +13,6 @@ import ( "github.com/plgd-dev/hub/v2/test/config" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" "github.com/plgd-dev/hub/v2/test/service" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -104,7 +103,7 @@ func TestClientGetResource(t *testing.T) { c := NewTestClient(t) defer func() { err := c.Close() - assert.NoError(t, err) + require.NoError(t, err) }() _, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) @@ -112,10 +111,10 @@ func TestClientGetResource(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + runctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() var got interface{} - err := c.GetResource(ctx, tt.args.deviceID, tt.args.href, &got, tt.args.opts...) + err := c.GetResource(runctx, tt.args.deviceID, tt.args.href, &got, tt.args.opts...) if tt.wantErr { require.Error(t, err) return diff --git a/grpc-gateway/client/maintenance_test.go b/grpc-gateway/client/maintenance_test.go index 6404029a3..7256a3b0e 100644 --- a/grpc-gateway/client/maintenance_test.go +++ b/grpc-gateway/client/maintenance_test.go @@ -10,7 +10,6 @@ import ( "github.com/plgd-dev/hub/v2/test/config" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" "github.com/plgd-dev/hub/v2/test/service" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -54,7 +53,7 @@ func TestClientFactoryReset(t *testing.T) { c := NewTestClient(t) defer func() { err := c.Close() - assert.NoError(t, err) + require.NoError(t, err) }() _, _ = test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) @@ -108,7 +107,7 @@ func TestClientReboot(t *testing.T) { c := NewTestClient(t) defer func() { err := c.Close() - assert.NoError(t, err) + require.NoError(t, err) }() _, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) diff --git a/grpc-gateway/client/observeDeviceResources.go b/grpc-gateway/client/observeDeviceResources.go index 8bca2b728..8ea852174 100644 --- a/grpc-gateway/client/observeDeviceResources.go +++ b/grpc-gateway/client/observeDeviceResources.go @@ -46,7 +46,7 @@ func (c *Client) ObserveDeviceResources(ctx context.Context, deviceID string, ha sub, err := c.NewDeviceSubscription(ctx, deviceID, &deviceResourcesObservation{ h: handler, removeSubscription: func() { - if _, err := c.stopObservingDeviceResources(ID.String()); err != nil { + if _, err = c.stopObservingDeviceResources(ID.String()); err != nil { handler.Error(fmt.Errorf("failed to stop device('%v') resources observation: %w", ID.String(), err)) } }, diff --git a/grpc-gateway/client/observeDeviceResources_test.go b/grpc-gateway/client/observeDeviceResources_test.go index bdf19df89..9a05ff6a8 100644 --- a/grpc-gateway/client/observeDeviceResources_test.go +++ b/grpc-gateway/client/observeDeviceResources_test.go @@ -13,7 +13,6 @@ import ( oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" pbTest "github.com/plgd-dev/hub/v2/test/pb" "github.com/plgd-dev/hub/v2/test/service" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -28,7 +27,7 @@ func TestObserveDeviceResourcesPublish(t *testing.T) { c := NewTestClient(t) defer func() { err := c.Close() - assert.NoError(t, err) + require.NoError(t, err) }() deviceID, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) defer shutdownDevSim() diff --git a/grpc-gateway/client/observeDevices_test.go b/grpc-gateway/client/observeDevices_test.go index df9943bb0..6f32642a2 100644 --- a/grpc-gateway/client/observeDevices_test.go +++ b/grpc-gateway/client/observeDevices_test.go @@ -2,6 +2,7 @@ package client_test import ( "context" + "errors" "fmt" "testing" @@ -11,7 +12,6 @@ import ( "github.com/plgd-dev/hub/v2/test/config" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" "github.com/plgd-dev/hub/v2/test/service" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -26,7 +26,7 @@ func TestObserveDevices(t *testing.T) { c := NewTestClient(t) defer func() { err := c.Close() - assert.NoError(t, err) + require.NoError(t, err) }() deviceID, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) @@ -43,7 +43,7 @@ func TestObserveDevices(t *testing.T) { select { case res = <-h.res: case <-ctx.Done(): - require.NoError(t, fmt.Errorf("timeout")) + require.NoError(t, errors.New("timeout")) } require.Equal(t, client.DevicesObservationEvent{ DeviceIDs: []string{deviceID}, @@ -53,7 +53,7 @@ func TestObserveDevices(t *testing.T) { select { case res = <-h.res: case <-ctx.Done(): - require.NoError(t, fmt.Errorf("timeout")) + require.NoError(t, errors.New("timeout")) } require.Equal(t, client.DevicesObservationEvent{ DeviceIDs: []string{deviceID}, @@ -64,7 +64,7 @@ func TestObserveDevices(t *testing.T) { select { case res = <-h.res: case <-ctx.Done(): - require.NoError(t, fmt.Errorf("timeout")) + require.NoError(t, errors.New("timeout")) } require.True(t, res.Event == client.DevicesObservationEvent_OFFLINE || res.Event == client.DevicesObservationEvent_UNREGISTERED) require.Equal(t, client.DevicesObservationEvent{ diff --git a/grpc-gateway/client/observeResource_test.go b/grpc-gateway/client/observeResource_test.go index a95e56221..cdeaca197 100644 --- a/grpc-gateway/client/observeResource_test.go +++ b/grpc-gateway/client/observeResource_test.go @@ -27,8 +27,8 @@ func TestObservingResource(t *testing.T) { c := NewTestClient(t) defer func() { - err := c.Close() - assert.NoError(t, err) + errC := c.Close() + require.NoError(t, errC) }() deviceID, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) defer shutdownDevSim() @@ -37,8 +37,8 @@ func TestObservingResource(t *testing.T) { id, err := c.ObserveResource(ctx, deviceID, configuration.ResourceURI, h) require.NoError(t, err) defer func() { - err := c.StopObservingResource(id) - require.NoError(t, err) + errS := c.StopObservingResource(id) + require.NoError(t, errS) }() name := "observe simulator" @@ -56,7 +56,7 @@ func TestObservingResource(t *testing.T) { require.Equal(t, name, d.Name) err = c.UpdateResource(ctx, deviceID, configuration.ResourceURI, map[string]interface{}{"n": test.TestDeviceName}, nil) - assert.NoError(t, err) + require.NoError(t, err) } func makeTestObservationHandler() *testObservationHandler { diff --git a/grpc-gateway/client/resourceSubscription.go b/grpc-gateway/client/resourceSubscription.go index 85e11bd56..abe5f9cc5 100644 --- a/grpc-gateway/client/resourceSubscription.go +++ b/grpc-gateway/client/resourceSubscription.go @@ -54,7 +54,7 @@ func NewResourceSubscription(ctx context.Context, resourceID *commands.ResourceI } if resourceContentChangedHandler == nil { - return nil, fmt.Errorf("invalid handler - it's supports: ResourceContentChangedHandler") + return nil, errors.New("invalid handler - it's supports: ResourceContentChangedHandler") } client, err := New(gwClient).SubscribeToEventsWithCurrentState(ctx, time.Minute) if err != nil { @@ -85,7 +85,7 @@ func NewResourceSubscription(ctx context.Context, resourceID *commands.ResourceI return nil, fmt.Errorf("unexpected event %+v", ev) } if op.GetErrorStatus().GetCode() != pb.Event_OperationProcessed_ErrorStatus_OK { - return nil, fmt.Errorf(op.GetErrorStatus().GetMessage()) + return nil, errors.New(op.GetErrorStatus().GetMessage()) } var wg sync.WaitGroup @@ -141,7 +141,7 @@ func (s *ResourceSubscription) handleCancel(cancel *pb.Event_SubscriptionCancele s.closeErrorHandler.OnClose() return } - s.closeErrorHandler.Error(fmt.Errorf(reason)) + s.closeErrorHandler.Error(errors.New(reason)) } func (s *ResourceSubscription) runRecv() { diff --git a/grpc-gateway/client/updateResource_test.go b/grpc-gateway/client/updateResource_test.go index b9161dd7a..f77e1e8f9 100644 --- a/grpc-gateway/client/updateResource_test.go +++ b/grpc-gateway/client/updateResource_test.go @@ -13,7 +13,6 @@ import ( "github.com/plgd-dev/hub/v2/test/config" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" "github.com/plgd-dev/hub/v2/test/service" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -97,18 +96,18 @@ func TestClientUpdateResource(t *testing.T) { c := NewTestClient(t) defer func() { - err := c.Close() - assert.NoError(t, err) + errC := c.Close() + require.NoError(t, errC) }() _, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) defer shutdownDevSim() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + runctx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() var got interface{} - err := c.UpdateResource(ctx, tt.args.deviceID, tt.args.href, tt.args.data, &got, tt.args.opts...) + err := c.UpdateResource(runctx, tt.args.deviceID, tt.args.href, tt.args.data, &got, tt.args.opts...) if tt.wantErr { require.Error(t, err) return @@ -135,7 +134,7 @@ func TestUpdateConfigurationName(t *testing.T) { c := NewTestClient(t) defer func() { err := c.Close() - assert.NoError(t, err) + require.NoError(t, err) }() deviceID, shutdownDevSim := test.OnboardDevSim(ctx, t, c.GrpcGatewayClient(), deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) defer shutdownDevSim() @@ -145,7 +144,7 @@ func TestUpdateConfigurationName(t *testing.T) { for _, link := range test.GetAllBackendResourceLinks() { var got interface{} err := c.GetResource(ctx, devID, link.Href, &got) - assert.NoError(t, err) + require.NoError(t, err) resourceData[link.Href] = got } return resourceData diff --git a/grpc-gateway/pb/README.md b/grpc-gateway/pb/README.md index 0cb9b99e9..50ea16d47 100644 --- a/grpc-gateway/pb/README.md +++ b/grpc-gateway/pb/README.md @@ -1491,6 +1491,7 @@ https://github.com/openconnectivityfoundation/core/blob/master/schemas/oic.links | audit_context | [AuditContext](#resourceaggregate-pb-AuditContext) | | | | event_metadata | [EventMetadata](#resourceaggregate-pb-EventMetadata) | | | | etag | [bytes](#bytes) | | etag of the resource used by twin synchronization | +| resource_types | [string](#string) | repeated | | | open_telemetry_carrier | [ResourceChanged.OpenTelemetryCarrierEntry](#resourceaggregate-pb-ResourceChanged-OpenTelemetryCarrierEntry) | repeated | Open telemetry data propagated to asynchronous events | @@ -1527,6 +1528,7 @@ https://github.com/openconnectivityfoundation/core/blob/master/schemas/oic.links | audit_context | [AuditContext](#resourceaggregate-pb-AuditContext) | | | | event_metadata | [EventMetadata](#resourceaggregate-pb-EventMetadata) | | | | valid_until | [int64](#int64) | | unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. | +| resource_types | [string](#string) | repeated | | | open_telemetry_carrier | [ResourceCreatePending.OpenTelemetryCarrierEntry](#resourceaggregate-pb-ResourceCreatePending-OpenTelemetryCarrierEntry) | repeated | Open telemetry data propagated to asynchronous events | @@ -1563,6 +1565,7 @@ https://github.com/openconnectivityfoundation/core/blob/master/schemas/oic.links | content | [Content](#resourceaggregate-pb-Content) | | | | audit_context | [AuditContext](#resourceaggregate-pb-AuditContext) | | | | event_metadata | [EventMetadata](#resourceaggregate-pb-EventMetadata) | | | +| resource_types | [string](#string) | repeated | | | open_telemetry_carrier | [ResourceCreated.OpenTelemetryCarrierEntry](#resourceaggregate-pb-ResourceCreated-OpenTelemetryCarrierEntry) | repeated | Open telemetry data propagated to asynchronous events | @@ -1599,6 +1602,7 @@ https://github.com/openconnectivityfoundation/core/blob/master/schemas/oic.links | event_metadata | [EventMetadata](#resourceaggregate-pb-EventMetadata) | | | | valid_until | [int64](#int64) | | unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. | | resource_interface | [string](#string) | | | +| resource_types | [string](#string) | repeated | | | open_telemetry_carrier | [ResourceDeletePending.OpenTelemetryCarrierEntry](#resourceaggregate-pb-ResourceDeletePending-OpenTelemetryCarrierEntry) | repeated | Open telemetry data propagated to asynchronous events | @@ -1635,6 +1639,7 @@ https://github.com/openconnectivityfoundation/core/blob/master/schemas/oic.links | content | [Content](#resourceaggregate-pb-Content) | | | | audit_context | [AuditContext](#resourceaggregate-pb-AuditContext) | | | | event_metadata | [EventMetadata](#resourceaggregate-pb-EventMetadata) | | | +| resource_types | [string](#string) | repeated | | | open_telemetry_carrier | [ResourceDeleted.OpenTelemetryCarrierEntry](#resourceaggregate-pb-ResourceDeleted-OpenTelemetryCarrierEntry) | repeated | Open telemetry data propagated to asynchronous events | @@ -1776,6 +1781,7 @@ https://github.com/openconnectivityfoundation/cloud-services/blob/master/swagger | event_metadata | [EventMetadata](#resourceaggregate-pb-EventMetadata) | | | | valid_until | [int64](#int64) | | unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. | | etag | [bytes](#bytes) | repeated | | +| resource_types | [string](#string) | repeated | | | open_telemetry_carrier | [ResourceRetrievePending.OpenTelemetryCarrierEntry](#resourceaggregate-pb-ResourceRetrievePending-OpenTelemetryCarrierEntry) | repeated | Open telemetry data propagated to asynchronous events | @@ -1813,6 +1819,7 @@ https://github.com/openconnectivityfoundation/cloud-services/blob/master/swagger | audit_context | [AuditContext](#resourceaggregate-pb-AuditContext) | | | | event_metadata | [EventMetadata](#resourceaggregate-pb-EventMetadata) | | | | etag | [bytes](#bytes) | | | +| resource_types | [string](#string) | repeated | | | open_telemetry_carrier | [ResourceRetrieved.OpenTelemetryCarrierEntry](#resourceaggregate-pb-ResourceRetrieved-OpenTelemetryCarrierEntry) | repeated | Open telemetry data propagated to asynchronous events | @@ -1852,6 +1859,7 @@ https://github.com/openconnectivityfoundation/cloud-services/blob/master/swagger | resource_delete_pendings | [ResourceDeletePending](#resourceaggregate-pb-ResourceDeletePending) | repeated | expired events will be removed by creating a new snapshot. | | audit_context | [AuditContext](#resourceaggregate-pb-AuditContext) | | | | event_metadata | [EventMetadata](#resourceaggregate-pb-EventMetadata) | | | +| resource_types | [string](#string) | repeated | | @@ -1872,6 +1880,7 @@ https://github.com/openconnectivityfoundation/cloud-services/blob/master/swagger | audit_context | [AuditContext](#resourceaggregate-pb-AuditContext) | | | | event_metadata | [EventMetadata](#resourceaggregate-pb-EventMetadata) | | | | valid_until | [int64](#int64) | | unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. | +| resource_types | [string](#string) | repeated | | | open_telemetry_carrier | [ResourceUpdatePending.OpenTelemetryCarrierEntry](#resourceaggregate-pb-ResourceUpdatePending-OpenTelemetryCarrierEntry) | repeated | Open telemetry data propagated to asynchronous events | @@ -1908,6 +1917,7 @@ https://github.com/openconnectivityfoundation/cloud-services/blob/master/swagger | content | [Content](#resourceaggregate-pb-Content) | | | | audit_context | [AuditContext](#resourceaggregate-pb-AuditContext) | | | | event_metadata | [EventMetadata](#resourceaggregate-pb-EventMetadata) | | | +| resource_types | [string](#string) | repeated | | | open_telemetry_carrier | [ResourceUpdated.OpenTelemetryCarrierEntry](#resourceaggregate-pb-ResourceUpdated-OpenTelemetryCarrierEntry) | repeated | Open telemetry data propagated to asynchronous events | diff --git a/grpc-gateway/pb/cancelCommands.pb.go b/grpc-gateway/pb/cancelCommands.pb.go index 785b145bb..073940ed0 100644 --- a/grpc-gateway/pb/cancelCommands.pb.go +++ b/grpc-gateway/pb/cancelCommands.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: grpc-gateway/pb/cancelCommands.proto package pb diff --git a/grpc-gateway/pb/devices.pb.go b/grpc-gateway/pb/devices.pb.go index 2ed0b6325..49f7d3df8 100644 --- a/grpc-gateway/pb/devices.pb.go +++ b/grpc-gateway/pb/devices.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: grpc-gateway/pb/devices.proto package pb @@ -12,7 +12,6 @@ import ( events "github.com/plgd-dev/hub/v2/resource-aggregate/events" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" - _ "google.golang.org/protobuf/types/known/structpb" reflect "reflect" sync "sync" ) @@ -2237,430 +2236,428 @@ var file_grpc_gateway_pb_devices_proto_rawDesc = []byte{ 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2d, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x62, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd0, - 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x79, 0x70, 0x65, 0x46, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x4d, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, - 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, - 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x46, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, - 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x21, - 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x4e, 0x4c, 0x49, - 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4f, 0x46, 0x46, 0x4c, 0x49, 0x4e, 0x45, 0x10, - 0x01, 0x22, 0x40, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x22, 0x36, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, - 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x22, 0x64, 0x0a, 0x17, 0x47, - 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x52, + 0x22, 0xd0, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x79, 0x70, - 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x22, 0xc6, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, - 0x6c, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, - 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x5c, 0x0a, 0x1d, 0x47, 0x65, - 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, - 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x69, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0b, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x65, - 0x74, 0x61, 0x67, 0x22, 0xeb, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x17, 0x68, - 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, - 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, - 0x52, 0x14, 0x68, 0x74, 0x74, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, + 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x4d, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x28, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, + 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x79, 0x70, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x22, 0x21, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x4e, + 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4f, 0x46, 0x46, 0x4c, 0x49, 0x4e, + 0x45, 0x10, 0x01, 0x22, 0x40, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x46, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x36, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, + 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x22, 0x64, 0x0a, + 0x17, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, + 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x74, + 0x79, 0x70, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x22, 0xc6, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, + 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, + 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x5c, 0x0a, 0x1d, + 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, + 0x65, 0x76, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x69, 0x0a, 0x10, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x41, + 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, + 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0xeb, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, + 0x17, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x02, + 0x18, 0x01, 0x52, 0x14, 0x68, 0x74, 0x74, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x79, 0x70, 0x65, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x52, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x22, 0x5b, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x22, 0xde, 0x01, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, + 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, + 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0c, + 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x12, 0x31, + 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, + 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x22, 0x53, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xa6, 0x08, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x67, 0x0a, 0x13, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, + 0x00, 0x52, 0x12, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x67, 0x0a, 0x13, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f, + 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, + 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x65, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x1a, 0xce, 0x05, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5d, 0x0a, 0x0c, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0e, 0x32, 0x3a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0b, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x46, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x17, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x14, 0x68, 0x74, 0x74, 0x70, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x72, 0x65, 0x66, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x68, 0x72, 0x65, 0x66, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, + 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x22, 0x5b, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xde, - 0x01, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, - 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, - 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x12, 0x31, 0x0a, 0x07, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, - 0x53, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x52, 0x04, - 0x64, 0x61, 0x74, 0x61, 0x22, 0xa6, 0x08, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x54, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x67, 0x0a, 0x13, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x54, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, - 0x12, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x67, 0x0a, 0x13, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f, 0x73, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, - 0x62, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, - 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x65, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x1a, 0xce, 0x05, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5d, 0x0a, 0x0c, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, - 0x32, 0x3a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, - 0x62, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x17, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x14, 0x68, 0x74, 0x74, 0x70, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1f, - 0x0a, 0x0b, 0x68, 0x72, 0x65, 0x66, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0a, 0x68, 0x72, 0x65, 0x66, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, - 0x4e, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x10, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, - 0x82, 0x03, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x47, - 0x49, 0x53, 0x54, 0x45, 0x52, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x52, - 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x44, - 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x55, - 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x22, 0x0a, 0x1e, 0x44, 0x45, 0x56, 0x49, - 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x55, 0x50, 0x44, 0x41, - 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, - 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, - 0x45, 0x44, 0x10, 0x06, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, - 0x5f, 0x55, 0x4e, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x07, 0x12, 0x1b, - 0x0a, 0x17, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, - 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x08, 0x12, 0x14, 0x0a, 0x10, 0x52, - 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, - 0x09, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x52, 0x45, - 0x54, 0x52, 0x49, 0x45, 0x56, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0a, - 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x52, 0x45, 0x54, - 0x52, 0x49, 0x45, 0x56, 0x45, 0x44, 0x10, 0x0b, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x53, 0x4f, - 0x55, 0x52, 0x43, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, - 0x49, 0x4e, 0x47, 0x10, 0x0c, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, - 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x0d, 0x12, 0x1b, 0x0a, 0x17, 0x52, - 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x50, - 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x53, 0x4f, - 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x0f, 0x12, 0x14, - 0x0a, 0x10, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, - 0x45, 0x44, 0x10, 0x10, 0x1a, 0x3d, 0x0a, 0x12, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x85, 0x15, - 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x55, 0x0a, 0x11, 0x64, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x48, 0x00, 0x52, 0x10, 0x64, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x12, 0x5b, - 0x0a, 0x13, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x65, 0x64, 0x48, 0x00, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x55, - 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x12, 0x5d, 0x0a, 0x12, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, - 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x73, 0x68, 0x65, 0x64, 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x63, 0x0a, 0x14, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x55, 0x6e, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, - 0x52, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x72, 0x22, 0x82, 0x03, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x0a, 0x52, + 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x55, + 0x4e, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1b, 0x0a, + 0x17, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, + 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x22, 0x0a, 0x1e, 0x44, 0x45, + 0x56, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x55, 0x50, + 0x44, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x16, + 0x0a, 0x12, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, + 0x53, 0x48, 0x45, 0x44, 0x10, 0x06, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, + 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x07, + 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x50, 0x44, + 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x08, 0x12, 0x14, 0x0a, + 0x10, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, + 0x44, 0x10, 0x09, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, + 0x52, 0x45, 0x54, 0x52, 0x49, 0x45, 0x56, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, + 0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x52, + 0x45, 0x54, 0x52, 0x49, 0x45, 0x56, 0x45, 0x44, 0x10, 0x0b, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x50, 0x45, + 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0c, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x0d, 0x12, 0x1b, 0x0a, + 0x17, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, + 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x0f, + 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x48, 0x41, + 0x4e, 0x47, 0x45, 0x44, 0x10, 0x10, 0x1a, 0x3d, 0x0a, 0x12, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, + 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x85, 0x15, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, + 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x55, 0x0a, 0x11, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x48, 0x00, 0x52, 0x10, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, + 0x12, 0x5b, 0x0a, 0x13, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x6e, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x48, 0x00, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x12, 0x5d, 0x0a, + 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x48, 0x00, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x12, 0x5b, 0x0a, 0x13, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x28, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, - 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x48, 0x00, 0x52, 0x12, 0x6f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, - 0x12, 0x61, 0x0a, 0x15, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, - 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x48, 0x00, 0x52, 0x14, 0x73, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x65, 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x0c, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0d, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x6b, - 0x0a, 0x19, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, - 0x65, 0x76, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x0e, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x48, 0x00, 0x52, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, - 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x58, 0x0a, 0x12, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, - 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, - 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, - 0x69, 0x65, 0x76, 0x65, 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x63, 0x0a, 0x14, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x73, 0x68, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, + 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x55, + 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, + 0x64, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x5b, 0x0a, 0x13, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x48, 0x00, 0x52, 0x12, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, + 0x65, 0x64, 0x12, 0x61, 0x0a, 0x15, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x48, 0x00, 0x52, + 0x14, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52, 0x0a, 0x10, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, - 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52, 0x0a, 0x10, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, - 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, - 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x12, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, - 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x78, 0x0a, 0x1e, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x1b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x65, 0x0a, 0x17, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, - 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x15, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x1a, 0xba, 0x02, 0x0a, - 0x10, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, - 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, - 0x12, 0x46, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x76, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, - 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, - 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, - 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, - 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, - 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, - 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, - 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xbe, 0x02, 0x0a, 0x12, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, - 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, - 0x46, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x78, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, - 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, - 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, - 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, - 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, - 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, - 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, - 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x90, 0x02, 0x0a, 0x12, 0x4f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, - 0x64, 0x12, 0x57, 0x0a, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, - 0x64, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0b, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0xa0, 0x01, 0x0a, 0x0b, 0x45, - 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4d, 0x0a, 0x04, 0x63, 0x6f, - 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x39, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, - 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, - 0x65, 0x64, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x43, - 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x28, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x06, 0x0a, 0x02, 0x4f, - 0x4b, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x0d, - 0x0a, 0x09, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02, 0x1a, 0x2e, 0x0a, - 0x14, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, - 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x42, 0x06, 0x0a, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x43, 0x0a, 0x0f, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, - 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, - 0x75, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, - 0x75, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x93, 0x06, 0x0a, 0x06, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, - 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4c, 0x0a, 0x11, - 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, - 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, - 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x6f, - 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1e, 0x0a, - 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x12, 0x36, 0x0a, - 0x17, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x70, 0x65, - 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, - 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x09, 0x20, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, + 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x12, 0x6b, 0x0a, 0x19, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x74, + 0x72, 0x69, 0x65, 0x76, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x48, 0x00, 0x52, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, + 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x58, 0x0a, + 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, + 0x76, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, + 0x65, 0x64, 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, + 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52, + 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x48, + 0x00, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x12, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x51, 0x0a, 0x10, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x73, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x67, 0x72, 0x70, - 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x0f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, - 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x73, 0x1a, 0xd3, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x40, - 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x5c, 0x0a, 0x14, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, - 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, - 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x77, 0x69, 0x6e, 0x53, 0x79, 0x6e, 0x63, 0x68, 0x72, - 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x74, 0x77, 0x69, 0x6e, 0x53, - 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, - 0x0a, 0x0c, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x74, 0x77, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x64, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x47, 0x0a, 0x0f, 0x4f, 0x77, 0x6e, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, - 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4f, 0x57, 0x4e, - 0x45, 0x44, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x44, 0x10, 0x02, 0x12, - 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x03, - 0x22, 0x40, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x22, 0xab, 0x01, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, - 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, - 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x22, 0x53, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x78, 0x0a, + 0x1e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, + 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x1b, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x65, 0x0a, 0x17, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x52, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xaf, 0x01, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x15, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x1a, 0xba, + 0x02, 0x0a, 0x10, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, + 0x64, 0x73, 0x12, 0x46, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x76, 0x0a, 0x16, 0x6f, 0x70, + 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, + 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, + 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, + 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, + 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, + 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xbe, 0x02, 0x0a, 0x12, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, + 0x73, 0x12, 0x46, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x78, 0x0a, 0x16, 0x6f, 0x70, 0x65, + 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, + 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, + 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, + 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, + 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, + 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x90, 0x02, 0x0a, + 0x12, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, + 0x73, 0x65, 0x64, 0x12, 0x57, 0x0a, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, + 0x73, 0x65, 0x64, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x0b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0xa0, 0x01, 0x0a, + 0x0b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4d, 0x0a, 0x04, + 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x39, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x28, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x06, 0x0a, + 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, + 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02, 0x1a, + 0x2e, 0x0a, 0x14, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x42, + 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x43, 0x0a, 0x0f, 0x4c, 0x6f, 0x63, 0x61, 0x6c, + 0x69, 0x7a, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, + 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, + 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x93, 0x06, 0x0a, + 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4c, + 0x0a, 0x11, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, + 0x69, 0x7a, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x6d, 0x61, 0x6e, 0x75, + 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, + 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x12, + 0x36, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x15, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x70, 0x65, + 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x51, 0x0a, 0x10, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x0f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x73, 0x1a, 0xd3, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x40, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x49, 0x64, 0x12, 0x31, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, - 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, - 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x22, 0x53, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, - 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x42, 0x2f, 0x5a, 0x2d, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d, - 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x2f, 0x76, 0x32, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x62, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x5c, 0x0a, 0x14, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x68, + 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x77, 0x69, 0x6e, 0x53, 0x79, 0x6e, 0x63, + 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x74, 0x77, 0x69, + 0x6e, 0x53, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x74, 0x77, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x47, 0x0a, 0x0f, 0x4f, 0x77, 0x6e, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, + 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4f, + 0x57, 0x4e, 0x45, 0x44, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x44, 0x10, + 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, + 0x10, 0x03, 0x22, 0x40, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, + 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x22, 0xab, 0x01, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, + 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, + 0x69, 0x76, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x22, 0x53, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, + 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xaf, 0x01, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, + 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, + 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x22, 0x53, 0x0a, 0x16, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x42, 0x2f, + 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67, + 0x64, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x2f, 0x76, 0x32, 0x2f, 0x67, 0x72, 0x70, + 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x62, 0x3b, 0x70, 0x62, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/grpc-gateway/pb/devices.proto b/grpc-gateway/pb/devices.proto index 3d345e9ef..54acada11 100644 --- a/grpc-gateway/pb/devices.proto +++ b/grpc-gateway/pb/devices.proto @@ -6,7 +6,6 @@ import "resource-aggregate/pb/commands.proto"; import "resource-aggregate/pb/events.proto"; import "resource-aggregate/pb/resources.proto"; import "identity-store/pb/events.proto"; -import "google/protobuf/struct.proto"; option go_package = "github.com/plgd-dev/hub/v2/grpc-gateway/pb;pb"; diff --git a/grpc-gateway/pb/doc.html b/grpc-gateway/pb/doc.html index 8d4c2586b..94218a2ae 100644 --- a/grpc-gateway/pb/doc.html +++ b/grpc-gateway/pb/doc.html @@ -4178,6 +4178,13 @@

ResourceChanged

etag of the resource used by twin synchronization

+ + resource_types + string + repeated +

+ + open_telemetry_carrier ResourceChanged.OpenTelemetryCarrierEntry @@ -4268,6 +4275,13 @@

ResourceCreatePending

unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever.

+ + resource_types + string + repeated +

+ + open_telemetry_carrier ResourceCreatePending.OpenTelemetryCarrierEntry @@ -4358,6 +4372,13 @@

ResourceCreated

+ + resource_types + string + repeated +

+ + open_telemetry_carrier ResourceCreated.OpenTelemetryCarrierEntry @@ -4448,6 +4469,13 @@

ResourceDeletePending

+ + resource_types + string + repeated +

+ + open_telemetry_carrier ResourceDeletePending.OpenTelemetryCarrierEntry @@ -4538,6 +4566,13 @@

ResourceDeleted

+ + resource_types + string + repeated +

+ + open_telemetry_carrier ResourceDeleted.OpenTelemetryCarrierEntry @@ -4877,6 +4912,13 @@

ResourceRetrievePending

+ + resource_types + string + repeated +

+ + open_telemetry_carrier ResourceRetrievePending.OpenTelemetryCarrierEntry @@ -4974,6 +5016,13 @@

ResourceRetrieved

+ + resource_types + string + repeated +

+ + open_telemetry_carrier ResourceRetrieved.OpenTelemetryCarrierEntry @@ -5085,6 +5134,13 @@

ResourceStateSnapshotTa

+ + resource_types + string + repeated +

+ + @@ -5144,6 +5200,13 @@

ResourceUpdatePending

unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever.

+ + resource_types + string + repeated +

+ + open_telemetry_carrier ResourceUpdatePending.OpenTelemetryCarrierEntry @@ -5234,6 +5297,13 @@

ResourceUpdated

+ + resource_types + string + repeated +

+ + open_telemetry_carrier ResourceUpdated.OpenTelemetryCarrierEntry diff --git a/grpc-gateway/pb/events.pb.go b/grpc-gateway/pb/events.pb.go index a82f73cf1..8849fd654 100644 --- a/grpc-gateway/pb/events.pb.go +++ b/grpc-gateway/pb/events.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: grpc-gateway/pb/events.proto package pb diff --git a/grpc-gateway/pb/getDevicesMetadata.pb.go b/grpc-gateway/pb/getDevicesMetadata.pb.go index 2ae1bd22a..e2a2dbd43 100644 --- a/grpc-gateway/pb/getDevicesMetadata.pb.go +++ b/grpc-gateway/pb/getDevicesMetadata.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: grpc-gateway/pb/getDevicesMetadata.proto package pb diff --git a/grpc-gateway/pb/getPendingCommands.pb.go b/grpc-gateway/pb/getPendingCommands.pb.go index 6e98207e9..65363c8a9 100644 --- a/grpc-gateway/pb/getPendingCommands.pb.go +++ b/grpc-gateway/pb/getPendingCommands.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: grpc-gateway/pb/getPendingCommands.proto package pb diff --git a/grpc-gateway/pb/getResources.go b/grpc-gateway/pb/getResources.go index 7596ab70f..78869173c 100644 --- a/grpc-gateway/pb/getResources.go +++ b/grpc-gateway/pb/getResources.go @@ -2,7 +2,7 @@ package pb import ( "encoding/base64" - "fmt" + "errors" "net/url" "strings" @@ -16,7 +16,7 @@ func parseQuery(m url.Values, query string) (err error) { var key string key, query, _ = strings.Cut(query, "&") if strings.Contains(key, ";") { - err = fmt.Errorf("invalid semicolon separator in query") + err = errors.New("invalid semicolon separator in query") continue } if key == "" { diff --git a/grpc-gateway/pb/hubConfiguration.go b/grpc-gateway/pb/hubConfiguration.go index b2ecf7036..b53fbf4ab 100644 --- a/grpc-gateway/pb/hubConfiguration.go +++ b/grpc-gateway/pb/hubConfiguration.go @@ -1,18 +1,22 @@ package pb +func copyScopes(scopes []string) []string { + if len(scopes) == 0 { + return nil + } + sc := make([]string, len(scopes)) + copy(sc, scopes) + return sc +} + func (r *WebOAuthClient) Clone() *WebOAuthClient { if r == nil { return nil } - var scopes []string - if len(r.Scopes) > 0 { - scopes = make([]string, len(r.Scopes)) - copy(scopes, r.Scopes) - } return &WebOAuthClient{ - ClientId: r.ClientId, - Audience: r.Audience, - Scopes: scopes, + ClientId: r.GetClientId(), + Audience: r.GetAudience(), + Scopes: copyScopes(r.GetScopes()), } } @@ -20,15 +24,10 @@ func (r *DeviceOAuthClient) Clone() *DeviceOAuthClient { if r == nil { return nil } - var scopes []string - if len(r.Scopes) > 0 { - scopes = make([]string, len(r.Scopes)) - copy(scopes, r.Scopes) - } return &DeviceOAuthClient{ - ProviderName: r.ProviderName, - ClientId: r.ClientId, - Audience: r.Audience, - Scopes: scopes, + ProviderName: r.GetProviderName(), + ClientId: r.GetClientId(), + Audience: r.GetAudience(), + Scopes: copyScopes(r.GetScopes()), } } diff --git a/grpc-gateway/pb/hubConfiguration.pb.go b/grpc-gateway/pb/hubConfiguration.pb.go index 2eddcc476..e33bc65ff 100644 --- a/grpc-gateway/pb/hubConfiguration.pb.go +++ b/grpc-gateway/pb/hubConfiguration.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: grpc-gateway/pb/hubConfiguration.proto package pb diff --git a/grpc-gateway/pb/hubConfiguration_test.go b/grpc-gateway/pb/hubConfiguration_test.go index 0f430f4a9..0287be823 100644 --- a/grpc-gateway/pb/hubConfiguration_test.go +++ b/grpc-gateway/pb/hubConfiguration_test.go @@ -14,7 +14,7 @@ func TestDeviceOAuthClient_Clone(t *testing.T) { } b := a.Clone() require.Equal(t, &a, b) - require.NotEqual(t, fmt.Sprintf("%p", &a.Scopes), fmt.Sprintf("%p", b.Scopes)) + require.NotEqual(t, fmt.Sprintf("%p", &a.Scopes), fmt.Sprintf("%p", b.GetScopes())) } func TestWebOAuthClient_Clone(t *testing.T) { @@ -24,5 +24,5 @@ func TestWebOAuthClient_Clone(t *testing.T) { } b := a.Clone() require.Equal(t, &a, b) - require.NotEqual(t, fmt.Sprintf("%p", &a.Scopes), fmt.Sprintf("%p", b.Scopes)) + require.NotEqual(t, fmt.Sprintf("%p", &a.Scopes), fmt.Sprintf("%p", b.GetScopes())) } diff --git a/grpc-gateway/pb/service.swagger.json b/grpc-gateway/pb/service.swagger.json index f42b11cca..f9d0ef04c 100644 --- a/grpc-gateway/pb/service.swagger.json +++ b/grpc-gateway/pb/service.swagger.json @@ -261,21 +261,7 @@ "in": "body", "required": true, "schema": { - "type": "object", - "properties": { - "twinEnabled": { - "type": "boolean" - }, - "twinForceSynchronization": { - "type": "boolean", - "description": "force synchronization IoT hub with the device resources and set twin_enabled to true. Use to address potential synchronization issues and prevent operational discrepancies." - }, - "timeToLive": { - "type": "string", - "format": "int64", - "description": "command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms)." - } - } + "$ref": "#/definitions/GrpcGatewayUpdateDeviceMetadataBody" } } ], @@ -896,7 +882,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/pbSubscribeToEvents" + "$ref": "#/definitions/grpcgatewaypbSubscribeToEvents" } } ], @@ -1024,6 +1010,23 @@ ], "default": "RESOURCE_CREATE" }, + "GrpcGatewayUpdateDeviceMetadataBody": { + "type": "object", + "properties": { + "twinEnabled": { + "type": "boolean" + }, + "twinForceSynchronization": { + "type": "boolean", + "description": "force synchronization IoT hub with the device resources and set twin_enabled to true. Use to address potential synchronization issues and prevent operational discrepancies." + }, + "timeToLive": { + "type": "string", + "format": "int64", + "description": "command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms)." + } + } + }, "OperationProcessedErrorStatus": { "type": "object", "properties": { @@ -1309,6 +1312,21 @@ } } }, + "grpcgatewaypbSubscribeToEvents": { + "type": "object", + "properties": { + "createSubscription": { + "$ref": "#/definitions/SubscribeToEventsCreateSubscription" + }, + "cancelSubscription": { + "$ref": "#/definitions/SubscribeToEventsCancelSubscription" + }, + "correlationId": { + "type": "string", + "title": "for pairing request SubscribeToEvents with Event.OperationProcessed" + } + } + }, "grpcgatewaypbUpdateDeviceMetadataResponse": { "type": "object", "properties": { @@ -1393,6 +1411,13 @@ "serviceId": { "type": "string", "description": "The service.ID, which identify the device being served, must be set when the status is ONLINE. However, during an OFFLINE event, they will be sed to empty values." + }, + "localEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The last local endpoints of the device, and it is set when the status is ONLINE." } } }, @@ -1765,6 +1790,12 @@ "format": "byte", "title": "etag of the resource used by twin synchronization" }, + "resourceTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "openTelemetryCarrier": { "type": "object", "additionalProperties": { @@ -1794,6 +1825,12 @@ "format": "int64", "description": "unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever." }, + "resourceTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "openTelemetryCarrier": { "type": "object", "additionalProperties": { @@ -1821,6 +1858,12 @@ "eventMetadata": { "$ref": "#/definitions/resourceaggregatepbEventMetadata" }, + "resourceTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "openTelemetryCarrier": { "type": "object", "additionalProperties": { @@ -1850,6 +1893,12 @@ "resourceInterface": { "type": "string" }, + "resourceTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "openTelemetryCarrier": { "type": "object", "additionalProperties": { @@ -1877,6 +1926,12 @@ "eventMetadata": { "$ref": "#/definitions/resourceaggregatepbEventMetadata" }, + "resourceTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "openTelemetryCarrier": { "type": "object", "additionalProperties": { @@ -2018,6 +2073,12 @@ "format": "byte" } }, + "resourceTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "openTelemetryCarrier": { "type": "object", "additionalProperties": { @@ -2049,6 +2110,12 @@ "type": "string", "format": "byte" }, + "resourceTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "openTelemetryCarrier": { "type": "object", "additionalProperties": { @@ -2104,6 +2171,12 @@ }, "eventMetadata": { "$ref": "#/definitions/resourceaggregatepbEventMetadata" + }, + "resourceTypes": { + "type": "array", + "items": { + "type": "string" + } } } }, @@ -2130,6 +2203,12 @@ "format": "int64", "description": "unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever." }, + "resourceTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "openTelemetryCarrier": { "type": "object", "additionalProperties": { @@ -2157,6 +2236,12 @@ "eventMetadata": { "$ref": "#/definitions/resourceaggregatepbEventMetadata" }, + "resourceTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "openTelemetryCarrier": { "type": "object", "additionalProperties": { @@ -2166,21 +2251,6 @@ } } }, - "pbSubscribeToEvents": { - "type": "object", - "properties": { - "createSubscription": { - "$ref": "#/definitions/SubscribeToEventsCreateSubscription" - }, - "cancelSubscription": { - "$ref": "#/definitions/SubscribeToEventsCancelSubscription" - }, - "correlationId": { - "type": "string", - "title": "for pairing request SubscribeToEvents with Event.OperationProcessed" - } - } - }, "pbTwinSynchronization": { "type": "object", "properties": { diff --git a/grpc-gateway/pb/service_grpc.pb.go b/grpc-gateway/pb/service_grpc.pb.go index 7de2eb1ac..a938d57cb 100644 --- a/grpc-gateway/pb/service_grpc.pb.go +++ b/grpc-gateway/pb/service_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc v5.26.1 // source: grpc-gateway/pb/service.proto package pb diff --git a/grpc-gateway/pb/updateDeviceMetadata.pb.go b/grpc-gateway/pb/updateDeviceMetadata.pb.go index 55e8bf3ee..d63b18787 100644 --- a/grpc-gateway/pb/updateDeviceMetadata.pb.go +++ b/grpc-gateway/pb/updateDeviceMetadata.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: grpc-gateway/pb/updateDeviceMetadata.proto package pb diff --git a/grpc-gateway/service/cancelPendingCommands_test.go b/grpc-gateway/service/cancelPendingCommands_test.go index e1be47df2..8b98a010c 100644 --- a/grpc-gateway/service/cancelPendingCommands_test.go +++ b/grpc-gateway/service/cancelPendingCommands_test.go @@ -19,7 +19,7 @@ func TestRequestHandlerCancelPendingCommands(t *testing.T) { client, resourcePendings, _, shutdown := pbTest.InitPendingEvents(ctx, t) defer shutdown() - require.Equal(t, len(resourcePendings), 4) + require.Len(t, resourcePendings, 4) type args struct { req *pb.CancelPendingCommandsRequest diff --git a/grpc-gateway/service/cancelPendingMetadataUpdates_test.go b/grpc-gateway/service/cancelPendingMetadataUpdates_test.go index 26f776eac..c7b8446d8 100644 --- a/grpc-gateway/service/cancelPendingMetadataUpdates_test.go +++ b/grpc-gateway/service/cancelPendingMetadataUpdates_test.go @@ -19,7 +19,7 @@ func TestRequestHandlerCancelPendingMetadataUpdates(t *testing.T) { client, _, devicePendings, shutdown := pbTest.InitPendingEvents(ctx, t) defer shutdown() - require.Equal(t, len(devicePendings), 2) + require.Len(t, devicePendings, 2) type args struct { req *pb.CancelPendingMetadataUpdatesRequest diff --git a/grpc-gateway/service/createAndDeleteResource_test.go b/grpc-gateway/service/createAndDeleteResource_test.go index 3214465a0..38866992a 100644 --- a/grpc-gateway/service/createAndDeleteResource_test.go +++ b/grpc-gateway/service/createAndDeleteResource_test.go @@ -58,7 +58,7 @@ func createSwitchResource(ctx context.Context, t *testing.T, c pb.GrpcGatewayCli }) require.NoError(t, err) switchData := pbTest.MakeCreateSwitchResourceResponseData(switchID) - want := pbTest.MakeResourceCreated(t, deviceID, test.TestResourceSwitchesHref, "", switchData) + want := pbTest.MakeResourceCreated(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "", switchData) pbTest.CmpResourceCreated(t, want, got.GetData()) } @@ -67,7 +67,7 @@ func deleteSwitchResource(ctx context.Context, t *testing.T, c pb.GrpcGatewayCli ResourceId: commands.NewResourceID(deviceID, test.TestResourceSwitchesInstanceHref(switchID)), }) require.NoError(t, err) - want := pbTest.MakeResourceDeleted(deviceID, test.TestResourceSwitchesInstanceHref(switchID), "") + want := pbTest.MakeResourceDeleted(deviceID, test.TestResourceSwitchesInstanceHref(switchID), test.TestResourceSwitchesInstanceResourceTypes, "") pbTest.CmpResourceDeleted(t, want, got.GetData()) } @@ -76,7 +76,7 @@ func createSwitchResourceExpectedEvents(t *testing.T, deviceID, subID, correlati SubscriptionId: subID, CorrelationId: correlationID, Type: &pb.Event_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, test.TestResourceSwitchesHref, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "", test.MakeSwitchResourceDefaultData()), }, } @@ -85,7 +85,7 @@ func createSwitchResourceExpectedEvents(t *testing.T, deviceID, subID, correlati SubscriptionId: subID, CorrelationId: correlationID, Type: &pb.Event_ResourceChanged{ - ResourceChanged: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesHref, "", + ResourceChanged: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "", []map[string]interface{}{ { "href": test.TestResourceSwitchesInstanceHref(switchID), @@ -105,7 +105,7 @@ func createSwitchResourceExpectedEvents(t *testing.T, deviceID, subID, correlati SubscriptionId: subID, CorrelationId: correlationID, Type: &pb.Event_ResourceCreated{ - ResourceCreated: pbTest.MakeResourceCreated(t, deviceID, test.TestResourceSwitchesHref, "", + ResourceCreated: pbTest.MakeResourceCreated(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "", test.MakeSwitchResourceData(map[string]interface{}{ "href": test.TestResourceSwitchesInstanceHref(switchID), "rep": map[string]interface{}{ @@ -144,7 +144,7 @@ func createSwitchResourceExpectedEvents(t *testing.T, deviceID, subID, correlati SubscriptionId: subID, CorrelationId: correlationID, Type: &pb.Event_ResourceChanged{ - ResourceChanged: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), "", + ResourceChanged: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), test.TestResourceSwitchesInstanceResourceTypes, "", map[string]interface{}{ "value": false, }), @@ -209,8 +209,9 @@ func deleteSwitchResourceExpectedEvents(t *testing.T, deviceID, subID, correlati CorrelationId: correlationID, Type: &pb.Event_ResourceDeletePending{ ResourceDeletePending: &events.ResourceDeletePending{ - ResourceId: commands.NewResourceID(deviceID, test.TestResourceSwitchesInstanceHref(switchID)), - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceId: commands.NewResourceID(deviceID, test.TestResourceSwitchesInstanceHref(switchID)), + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: test.TestResourceSwitchesInstanceResourceTypes, }, }, } @@ -219,7 +220,7 @@ func deleteSwitchResourceExpectedEvents(t *testing.T, deviceID, subID, correlati SubscriptionId: subID, CorrelationId: correlationID, Type: &pb.Event_ResourceDeleted{ - ResourceDeleted: pbTest.MakeResourceDeleted(deviceID, test.TestResourceSwitchesInstanceHref(switchID), ""), + ResourceDeleted: pbTest.MakeResourceDeleted(deviceID, test.TestResourceSwitchesInstanceHref(switchID), test.TestResourceSwitchesInstanceResourceTypes, ""), }, } @@ -239,11 +240,11 @@ func deleteSwitchResourceExpectedEvents(t *testing.T, deviceID, subID, correlati SubscriptionId: subID, CorrelationId: correlationID, Type: &pb.Event_ResourceChanged{ - ResourceChanged: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesHref, "", []interface{}{}), + ResourceChanged: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "", []interface{}{}), }, } - res := pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), "", nil) + res := pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), test.TestResourceSwitchesInstanceResourceTypes, "", nil) res.Status = commands.Status_NOT_FOUND res.Content.CoapContentFormat = -1 res.Content.ContentType = "" @@ -297,7 +298,7 @@ func TestCreateAndDeleteResource(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/grpc-gateway/service/createResource_test.go b/grpc-gateway/service/createResource_test.go index 8ca708517..28fe924cf 100644 --- a/grpc-gateway/service/createResource_test.go +++ b/grpc-gateway/service/createResource_test.go @@ -151,7 +151,7 @@ func TestRequestHandlerCreateResource(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -173,7 +173,7 @@ func TestRequestHandlerCreateResource(t *testing.T) { return } require.NoError(t, err) - resp := pbTest.MakeResourceCreated(t, deviceID, tt.args.href, "", tt.wantData) + resp := pbTest.MakeResourceCreated(t, deviceID, tt.args.href, test.TestResourceSwitchesResourceTypes, "", tt.wantData) pbTest.CmpResourceCreated(t, resp, got.GetData()) }) } diff --git a/grpc-gateway/service/deleteDevices.go b/grpc-gateway/service/deleteDevices.go index 134b500a6..692ab8be2 100644 --- a/grpc-gateway/service/deleteDevices.go +++ b/grpc-gateway/service/deleteDevices.go @@ -28,7 +28,7 @@ func partitionDeletedDevices(expected, actual []string) ([]string, []string) { func (r *RequestHandler) DeleteDevices(ctx context.Context, req *pb.DeleteDevicesRequest) (*pb.DeleteDevicesResponse, error) { // get unique non-empty ids - deviceIDs, _ := strings.Split(strings.Unique(req.DeviceIdFilter), func(s string) bool { + deviceIDs, _ := strings.Split(strings.Unique(req.GetDeviceIdFilter()), func(s string) bool { return s != "" }) diff --git a/grpc-gateway/service/deleteDevices_test.go b/grpc-gateway/service/deleteDevices_test.go index 40b742fbf..210bdd884 100644 --- a/grpc-gateway/service/deleteDevices_test.go +++ b/grpc-gateway/service/deleteDevices_test.go @@ -62,7 +62,7 @@ func TestRequestHandlerDeleteDevices(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -78,7 +78,7 @@ func TestRequestHandlerDeleteDevices(t *testing.T) { t.Run(tt.name, func(t *testing.T) { resp, err := c.DeleteDevices(ctx, tt.args.req) require.NoError(t, err) - require.Equal(t, tt.want.DeviceIds, resp.DeviceIds) + require.Equal(t, tt.want.GetDeviceIds(), resp.GetDeviceIds()) }) } } @@ -87,7 +87,7 @@ func waitForOperationProcessedEvent(t *testing.T, subClient pb.GrpcGateway_Subsc ev, err := subClient.Recv() require.NoError(t, err) expectedEvent := &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), CorrelationId: corID, Type: &pb.Event_OperationProcessed_{ OperationProcessed: &pb.Event_OperationProcessed{ @@ -105,7 +105,7 @@ func waitForStopEvent(t *testing.T, subClient pb.GrpcGateway_SubscribeToEventsCl require.NoError(t, err) expectedEvent := &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), CorrelationId: corID, Type: &pb.Event_DeviceUnregistered_{ DeviceUnregistered: &pb.Event_DeviceUnregistered{ @@ -129,7 +129,7 @@ func TestRequestHandlerReconnectAfterDeleteDevice(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -161,7 +161,7 @@ func TestRequestHandlerReconnectAfterDeleteDevice(t *testing.T) { DeviceIdFilter: []string{deviceID}, }) require.NoError(t, err) - require.Equal(t, []string{deviceID}, resp.DeviceIds) + require.Equal(t, []string{deviceID}, resp.GetDeviceIds()) waitForStopEvent(t, subClient, deviceID, correlationID) err = subClient.CloseSend() require.NoError(t, err) diff --git a/grpc-gateway/service/deleteResource_test.go b/grpc-gateway/service/deleteResource_test.go index 0b66e8559..d73b0a64d 100644 --- a/grpc-gateway/service/deleteResource_test.go +++ b/grpc-gateway/service/deleteResource_test.go @@ -105,7 +105,7 @@ func TestRequestHandlerDeleteResource(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -131,7 +131,7 @@ func TestRequestHandlerDeleteResource(t *testing.T) { } require.NoError(t, err) - want := pbTest.MakeResourceDeleted(deviceID, tt.args.href, "") + want := pbTest.MakeResourceDeleted(deviceID, tt.args.href, test.TestResourceSwitchesInstanceResourceTypes, "") pbTest.CmpResourceDeleted(t, want, got.GetData()) }) } @@ -147,7 +147,7 @@ func TestRequestHandlerDeleteResourceAfterUnpublish(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -187,8 +187,8 @@ func TestRequestHandlerDeleteResourceAfterUnpublish(t *testing.T) { }, }) require.NoError(t, err) - require.Len(t, respUnpublish.UnpublishedHrefs, 1) - require.Equal(t, respUnpublish.UnpublishedHrefs[0], test.TestResourceSwitchesInstanceHref(switchID2)) + require.Len(t, respUnpublish.GetUnpublishedHrefs(), 1) + require.Equal(t, respUnpublish.GetUnpublishedHrefs()[0], test.TestResourceSwitchesInstanceHref(switchID2)) // for update resource-directory cache time.Sleep(time.Second) @@ -264,7 +264,7 @@ func TestRequestHandlerBatchDeleteResource(t *testing.T) { href: test.TestResourceSwitchesHref, }, want: func() *events.ResourceDeleted { - rdel := pbTest.MakeResourceDeleted(deviceID, test.TestResourceSwitchesHref, "") + rdel := pbTest.MakeResourceDeleted(deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "") links := test.CollectionLinkRepresentations{} for _, switchID := range switchIDs { links = append(links, test.CollectionLinkRepresentation{ @@ -289,7 +289,7 @@ func TestRequestHandlerBatchDeleteResource(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/grpc-gateway/service/getDevicesMetadata_test.go b/grpc-gateway/service/getDevicesMetadata_test.go index aaf941553..9ee9c7612 100644 --- a/grpc-gateway/service/getDevicesMetadata_test.go +++ b/grpc-gateway/service/getDevicesMetadata_test.go @@ -126,7 +126,7 @@ func TestRequestHandlerGetDevicesMetadata(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/grpc-gateway/service/getDevices_test.go b/grpc-gateway/service/getDevices_test.go index c074499a1..26412bdbb 100644 --- a/grpc-gateway/service/getDevices_test.go +++ b/grpc-gateway/service/getDevices_test.go @@ -70,7 +70,7 @@ func TestRequestHandlerGetDevices(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -96,7 +96,7 @@ func TestRequestHandlerGetDevices(t *testing.T) { break } require.NoError(t, err) - assert.NotEmpty(t, dev.ProtocolIndependentId) + assert.NotEmpty(t, dev.GetProtocolIndependentId()) assert.NotEmpty(t, dev.GetData().GetContent().GetData()) assert.NotEmpty(t, dev.GetMetadata().GetConnection().GetServiceId()) devices = append(devices, dev) diff --git a/grpc-gateway/service/getEvents_test.go b/grpc-gateway/service/getEvents_test.go index bdbb443a1..e468a32c1 100644 --- a/grpc-gateway/service/getEvents_test.go +++ b/grpc-gateway/service/getEvents_test.go @@ -49,7 +49,7 @@ func TestRequestHandlerGetEvents(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -63,7 +63,7 @@ func TestRequestHandlerGetEvents(t *testing.T) { defer shutdownDevSim() events := getAllEvents(ctx, t, c) - require.True(t, len(events) > 0) + require.NotEmpty(t, events) type args struct { req *pb.GetEventsRequest diff --git a/grpc-gateway/service/getHubConfiguration_test.go b/grpc-gateway/service/getHubConfiguration_test.go index e374ff4fc..2de53c938 100644 --- a/grpc-gateway/service/getHubConfiguration_test.go +++ b/grpc-gateway/service/getHubConfiguration_test.go @@ -36,7 +36,7 @@ func TestRequestHandlerGetHubConfiguration(t *testing.T) { tearDown := service.SetUp(ctx, t) defer tearDown() - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -51,7 +51,7 @@ func TestRequestHandlerGetHubConfiguration(t *testing.T) { got, err := c.GetHubConfiguration(ctxWithoutToken, &pb.HubConfigurationRequest{}) require.NoError(t, err) require.NotEmpty(t, got.GetBuildInfo()) - got.BuildInfo.ReleaseUrl = expected.BuildInfo.ReleaseUrl + got.BuildInfo.ReleaseUrl = expected.GetBuildInfo().GetReleaseUrl() pbTest.CmpHubConfigurationResponse(t, tt.want, got) }) } diff --git a/grpc-gateway/service/getResourceFromDevice_test.go b/grpc-gateway/service/getResourceFromDevice_test.go index 27afd55df..048728654 100644 --- a/grpc-gateway/service/getResourceFromDevice_test.go +++ b/grpc-gateway/service/getResourceFromDevice_test.go @@ -24,6 +24,7 @@ import ( "github.com/plgd-dev/hub/v2/test/config" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" pbTest "github.com/plgd-dev/hub/v2/test/pb" + "github.com/plgd-dev/hub/v2/test/sdk" "github.com/plgd-dev/hub/v2/test/service" "github.com/stretchr/testify/require" "google.golang.org/grpc" @@ -71,7 +72,7 @@ func TestRequestHandlerGetResourceFromDevice(t *testing.T) { TimeToLive: int64(time.Hour), }, }, - want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "name": "Light", "power": uint64(0), @@ -87,7 +88,7 @@ func TestRequestHandlerGetResourceFromDevice(t *testing.T) { TimeToLive: int64(time.Hour), }, }, - want: pbTest.MakeResourceRetrieved(t, deviceID, device.ResourceURI, "", + want: pbTest.MakeResourceRetrieved(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "n": deviceName, "di": deviceID, @@ -106,7 +107,7 @@ func TestRequestHandlerGetResourceFromDevice(t *testing.T) { TimeToLive: int64(time.Hour), }, }, - want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceSwitchesHref, "", + want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "", []map[string]interface{}{ { "href": test.TestResourceSwitchesInstanceHref(switchID), @@ -129,7 +130,7 @@ func TestRequestHandlerGetResourceFromDevice(t *testing.T) { TimeToLive: int64(time.Hour), }, }, - want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), "", + want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), test.TestResourceSwitchesInstanceResourceTypes, "", map[string]interface{}{ "value": false, }, @@ -145,7 +146,7 @@ func TestRequestHandlerGetResourceFromDevice(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -174,12 +175,12 @@ func TestRequestHandlerGetResourceFromDevice(t *testing.T) { } func validateETags(ctx context.Context, t *testing.T, c pb.GrpcGatewayClient, deviceID, href string) { - sdkClient, err := test.NewSDKClient() + sdkClient, err := sdk.NewClient() require.NoError(t, err) defer func() { - err := sdkClient.Close(context.Background()) - require.NoError(t, err) + errC := sdkClient.Close(context.Background()) + require.NoError(t, errC) }() // get resource from device via SDK @@ -200,7 +201,7 @@ func validateETags(ctx context.Context, t *testing.T, c pb.GrpcGatewayClient, de Etag: [][]byte{cfg2.GetData().GetEtag()}, }) require.NoError(t, err) - require.Equal(t, checkTag.GetData().GetStatus(), commands.Status_NOT_MODIFIED) + require.Equal(t, commands.Status_NOT_MODIFIED, checkTag.GetData().GetStatus()) require.Empty(t, checkTag.GetData().GetContent().GetData()) require.Empty(t, checkTag.GetData().GetContent().GetContentType()) require.Equal(t, int32(-1), checkTag.GetData().GetContent().GetCoapContentFormat()) @@ -253,7 +254,7 @@ func TestRequestHandlerCheckResourceETag(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/grpc-gateway/service/getResourceLinks_test.go b/grpc-gateway/service/getResourceLinks_test.go index 5d8107b0f..b79b3e50b 100644 --- a/grpc-gateway/service/getResourceLinks_test.go +++ b/grpc-gateway/service/getResourceLinks_test.go @@ -36,7 +36,7 @@ func TestRequestHandlerGetResourceLinks(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/grpc-gateway/service/getResources_test.go b/grpc-gateway/service/getResources_test.go index a92ed0017..e16e45e11 100644 --- a/grpc-gateway/service/getResources_test.go +++ b/grpc-gateway/service/getResources_test.go @@ -34,7 +34,7 @@ func TestRequestHandlerGetResources(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -118,7 +118,7 @@ func TestRequestHandlerGetResources(t *testing.T) { want: []*pb.Resource{ { Types: []string{types.CORE_LIGHT}, - Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "state": false, "power": uint64(0), @@ -153,7 +153,8 @@ func TestRequestHandlerGetResources(t *testing.T) { Content: &commands.Content{ CoapContentFormat: -1, }, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, }, }, @@ -168,7 +169,7 @@ func TestRequestHandlerGetResources(t *testing.T) { want: []*pb.Resource{ { Types: []string{types.BINARY_SWITCH}, - Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), "", + Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), test.TestResourceSwitchesInstanceResourceTypes, "", map[string]interface{}{ "value": false, }), diff --git a/grpc-gateway/service/subscribeToEvents_test.go b/grpc-gateway/service/subscribeToEvents_test.go index 8af9dc33b..60af3bc2b 100644 --- a/grpc-gateway/service/subscribeToEvents_test.go +++ b/grpc-gateway/service/subscribeToEvents_test.go @@ -51,7 +51,7 @@ func TestRequestHandlerSubscribeToEvents(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -201,7 +201,7 @@ func TestRequestHandlerSubscribeToEvents(t *testing.T) { require.NoError(t, err) defer func() { errC := client.CloseSend() - assert.NoError(t, errC) + require.NoError(t, errC) }() var wg sync.WaitGroup wg.Add(1) @@ -209,14 +209,14 @@ func TestRequestHandlerSubscribeToEvents(t *testing.T) { defer wg.Done() var events []*pb.Event for range tt.want { - ev, err := client.Recv() - if errors.Is(err, io.EOF) { + ev, errR := client.Recv() + if errors.Is(errR, io.EOF) { break } - require.NoError(t, err) + assert.NoError(t, errR) events = append(events, ev) } - pbTest.CmpEvents(t, tt.want, events) + pbTest.AssertCmpEvents(t, tt.want, events) }() err = client.Send(tt.args.sub) require.NoError(t, err) @@ -234,7 +234,7 @@ func TestRequestHandlerSubscribeForCreateEvents(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -265,7 +265,7 @@ func TestRequestHandlerSubscribeForCreateEvents(t *testing.T) { ev, err := client.Recv() require.NoError(t, err) expectedEvent := &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: pbTest.OperationProcessedOK(), CorrelationId: "testToken", } @@ -278,10 +278,10 @@ func TestRequestHandlerSubscribeForCreateEvents(t *testing.T) { ev, err = client.Recv() require.NoError(t, err) pbTest.CmpEvent(t, &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), CorrelationId: "testToken", Type: &pb.Event_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, test.TestResourceSwitchesHref, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "", switchData), }, }, ev, "") @@ -299,10 +299,10 @@ func TestRequestHandlerSubscribeForCreateEvents(t *testing.T) { ev, err = client.Recv() require.NoError(t, err) pbTest.CmpEvent(t, &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), CorrelationId: "testToken", Type: &pb.Event_ResourceCreated{ - ResourceCreated: pbTest.MakeResourceCreated(t, deviceID, test.TestResourceSwitchesHref, "", switchData), + ResourceCreated: pbTest.MakeResourceCreated(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "", switchData), }, }, ev, "") } @@ -316,7 +316,7 @@ func TestRequestHandlerSubscribeForHrefEvents(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -346,7 +346,7 @@ func TestRequestHandlerSubscribeForHrefEvents(t *testing.T) { ev, err := client.Recv() require.NoError(t, err) expectedEvent := &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: pbTest.OperationProcessedOK(), CorrelationId: "testToken", } @@ -364,10 +364,10 @@ func TestRequestHandlerSubscribeForHrefEvents(t *testing.T) { } if ev.GetResourceCreatePending() != nil { pbTest.CmpEvent(t, &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), CorrelationId: "testToken", Type: &pb.Event_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, test.TestResourceSwitchesHref, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "", switchData), }, }, ev, "") @@ -395,10 +395,10 @@ func TestRequestHandlerSubscribeForHrefEvents(t *testing.T) { } if ev.GetResourceCreated() != nil { pbTest.CmpEvent(t, &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), CorrelationId: "testToken", Type: &pb.Event_ResourceCreated{ - ResourceCreated: pbTest.MakeResourceCreated(t, deviceID, test.TestResourceSwitchesHref, "", switchData), + ResourceCreated: pbTest.MakeResourceCreated(t, deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "", switchData), }, }, ev, "") break @@ -438,7 +438,7 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceUpdatePending{ - ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -479,13 +479,14 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { DeviceId: deviceID, Href: platform.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: []string{platform.ResourceType}, }, }, }, { Command: &pb.PendingCommand_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -498,13 +499,14 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, { Command: &pb.PendingCommand_ResourceUpdatePending{ - ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -529,7 +531,8 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { DeviceId: deviceID, Href: platform.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: []string{platform.ResourceType}, }, }, }, @@ -547,7 +550,7 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -573,7 +576,8 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -591,7 +595,7 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceUpdatePending{ - ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -645,7 +649,7 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -663,9 +667,9 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { secureGWShutdown() createFn := func(timeToLive time.Duration) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + createCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.CreateResource(ctx, &pb.CreateResourceRequest{ + _, errC := c.CreateResource(createCtx, &pb.CreateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -675,27 +679,27 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { }, TimeToLive: int64(timeToLive), }) - require.Error(t, err) + require.Error(t, errC) } createFn(time.Millisecond * 500) // for test expired event createFn(0) retrieveFn := func(timeToLive time.Duration) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + retrieveCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.GetResourceFromDevice(ctx, &pb.GetResourceFromDeviceRequest{ + _, errG := c.GetResourceFromDevice(retrieveCtx, &pb.GetResourceFromDeviceRequest{ ResourceId: commands.NewResourceID(deviceID, platform.ResourceURI), TimeToLive: int64(timeToLive), }) - require.Error(t, err) + require.Error(t, errG) } retrieveFn(time.Millisecond * 500) // for test expired event retrieveFn(0) updateFn := func(timeToLive time.Duration) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateResource(ctx, &pb.UpdateResourceRequest{ + _, errU := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -705,32 +709,32 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { }, TimeToLive: int64(timeToLive), }) - require.Error(t, err) + require.Error(t, errU) } updateFn(time.Millisecond * 500) // for test expired event updateFn(0) deleteFn := func(timeToLive time.Duration) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + deleteCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.DeleteResource(ctx, &pb.DeleteResourceRequest{ + _, errD := c.DeleteResource(deleteCtx, &pb.DeleteResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), TimeToLive: int64(timeToLive), }) - require.Error(t, err) + require.Error(t, errD) } deleteFn(time.Millisecond * 500) // for test expired event deleteFn(0) updateDeviceMetadataFn := func(timeToLive time.Duration) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateDeviceMetadata(ctx, &pb.UpdateDeviceMetadataRequest{ + _, errU := c.UpdateDeviceMetadata(updateCtx, &pb.UpdateDeviceMetadataRequest{ DeviceId: deviceID, TwinEnabled: false, TimeToLive: int64(timeToLive), }) - require.Error(t, err) + require.Error(t, errU) } updateDeviceMetadataFn(time.Millisecond * 500) // for test expired event updateDeviceMetadataFn(0) // for test expired event @@ -751,12 +755,12 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) { ev, err := client.Recv() require.NoError(t, err) expectedEvent := &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: pbTest.OperationProcessedOK(), CorrelationId: correlationID, } test.CheckProtobufs(t, expectedEvent, ev, test.RequireToCheckFunc(require.Equal)) - subscriptionID := ev.SubscriptionId + subscriptionID := ev.GetSubscriptionId() fmt.Printf("sub %v\n", subscriptionID) values := make([]*pb.PendingCommand, 0, 1) @@ -860,17 +864,17 @@ func TestRequestHandlerIssue270(t *testing.T) { ev, err := client.Recv() require.NoError(t, err) expectedEvent := &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: pbTest.OperationProcessedOK(), CorrelationId: "testToken", } - fmt.Printf("SUBSCRIPTION ID: %v\n", ev.SubscriptionId) + fmt.Printf("SUBSCRIPTION ID: %v\n", ev.GetSubscriptionId()) test.CheckProtobufs(t, expectedEvent, ev, test.RequireToCheckFunc(require.Equal)) ev, err = client.Recv() require.NoError(t, err) expectedEvent = &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: &pb.Event_DeviceRegistered_{ DeviceRegistered: &pb.Event_DeviceRegistered{ DeviceIds: []string{}, @@ -887,7 +891,7 @@ func TestRequestHandlerIssue270(t *testing.T) { ev, err = client.Recv() require.NoError(t, err) expectedEvent = &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: &pb.Event_DeviceRegistered_{ DeviceRegistered: &pb.Event_DeviceRegistered{ DeviceIds: []string{deviceID}, @@ -903,7 +907,7 @@ func TestRequestHandlerIssue270(t *testing.T) { ev, err = client.Recv() require.NoError(t, err) pbTest.CmpEvent(t, &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: &pb.Event_DeviceMetadataUpdated{ DeviceMetadataUpdated: &events.DeviceMetadataUpdated{ DeviceId: deviceID, @@ -931,7 +935,7 @@ func TestRequestHandlerIssue270(t *testing.T) { if ev.GetDeviceUnregistered() != nil { expectedEvent = &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: &pb.Event_DeviceUnregistered_{ DeviceUnregistered: &pb.Event_DeviceUnregistered{ DeviceIds: []string{deviceID}, @@ -962,7 +966,7 @@ func waitForDevice(t *testing.T, client pb.GrpcGateway_SubscribeToEventsClient, // this alternate to multiple values ev.GetDeviceMetadataUpdated().TwinSynchronization = nil pbTest.CmpEvent(t, &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: &pb.Event_DeviceMetadataUpdated{ DeviceMetadataUpdated: &events.DeviceMetadataUpdated{ DeviceId: deviceID, @@ -1037,7 +1041,7 @@ func TestCoAPGatewayServiceHeartbeat(t *testing.T) { ev, err := client.Recv() require.NoError(t, err) expectedEvent := &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: pbTest.OperationProcessedOK(), CorrelationId: "testToken", } @@ -1067,7 +1071,7 @@ func TestCoAPGatewayServiceHeartbeat(t *testing.T) { ev, err = client.Recv() require.NoError(t, err) pbTest.CmpEvent(t, &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: &pb.Event_DeviceMetadataUpdated{ DeviceMetadataUpdated: &events.DeviceMetadataUpdated{ DeviceId: deviceID, @@ -1108,7 +1112,7 @@ func TestCoAPGatewayServiceHeartbeat(t *testing.T) { ev, err = client.Recv() require.NoError(t, err) pbTest.CmpEvent(t, &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: &pb.Event_DeviceMetadataUpdated{ DeviceMetadataUpdated: &events.DeviceMetadataUpdated{ DeviceId: deviceID, diff --git a/grpc-gateway/service/updateDeviceMetadata_test.go b/grpc-gateway/service/updateDeviceMetadata_test.go index b9f3a26a3..74a5cea9d 100644 --- a/grpc-gateway/service/updateDeviceMetadata_test.go +++ b/grpc-gateway/service/updateDeviceMetadata_test.go @@ -3,7 +3,7 @@ package service_test import ( "context" "crypto/tls" - "fmt" + "errors" "testing" "time" @@ -25,7 +25,6 @@ import ( "github.com/plgd-dev/hub/v2/test/config" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" "github.com/plgd-dev/hub/v2/test/service" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/credentials" @@ -107,7 +106,7 @@ func (f *deviceMetadataUpdatedFilter) WaitForEvent(t time.Duration, correlationI return &ev, nil } case <-time.After(time.Until(deadline)): - return nil, fmt.Errorf("timeout") + return nil, errors.New("timeout") } } } @@ -122,7 +121,7 @@ func TestRequestHandlerUpdateDeviceMetadataTwinEnabled(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -157,10 +156,10 @@ func TestRequestHandlerUpdateDeviceMetadataTwinEnabled(t *testing.T) { obsDeviceMetadataUpdated, err := s.Subscribe(ctx, uuid.New().String(), utils.GetDeviceMetadataEventSubject("*", deviceID, (&events.DeviceMetadataUpdated{}).EventType()), deviceMetadataUpdatedFilter) require.NoError(t, err) defer func() { - err := obs.Close() - assert.NoError(t, err) - err = obsDeviceMetadataUpdated.Close() - assert.NoError(t, err) + errC := obs.Close() + require.NoError(t, errC) + errC = obsDeviceMetadataUpdated.Close() + require.NoError(t, errC) }() _, err = c.UpdateDeviceMetadata(ctx, &pb.UpdateDeviceMetadataRequest{ @@ -176,12 +175,12 @@ func TestRequestHandlerUpdateDeviceMetadataTwinEnabled(t *testing.T) { }) require.NoError(t, err) require.False(t, ev.GetData().GetTwinEnabled()) - require.Equal(t, ev.GetData().GetTwinSynchronization().GetState(), commands.TwinSynchronization_DISABLED) + require.Equal(t, commands.TwinSynchronization_DISABLED, ev.GetData().GetTwinSynchronization().GetState()) deviceMetadataUpdated, err := deviceMetadataUpdatedFilter.WaitForEvent(time.Second, ev.GetData().GetAuditContext().GetCorrelationId()) require.NoError(t, err) require.False(t, deviceMetadataUpdated.GetTwinEnabled()) - require.Equal(t, deviceMetadataUpdated.GetTwinSynchronization().GetState(), commands.TwinSynchronization_DISABLED) + require.Equal(t, commands.TwinSynchronization_DISABLED, deviceMetadataUpdated.GetTwinSynchronization().GetState()) _, err = c.UpdateResource(ctx, &pb.UpdateResourceRequest{ ResourceInterface: interfaces.OC_IF_BASELINE, @@ -215,12 +214,12 @@ func TestRequestHandlerUpdateDeviceMetadataTwinEnabled(t *testing.T) { }) require.NoError(t, err) require.True(t, ev.GetData().GetTwinEnabled()) - require.NotEqual(t, ev.GetData().GetTwinSynchronization().GetState(), commands.TwinSynchronization_DISABLED) + require.NotEqual(t, commands.TwinSynchronization_DISABLED, ev.GetData().GetTwinSynchronization().GetState()) deviceMetadataUpdated, err = deviceMetadataUpdatedFilter.WaitForEvent(time.Second, ev.GetData().GetAuditContext().GetCorrelationId()) require.NoError(t, err) require.True(t, deviceMetadataUpdated.GetTwinEnabled()) - require.NotEqual(t, deviceMetadataUpdated.GetTwinSynchronization().GetState(), commands.TwinSynchronization_DISABLED) + require.NotEqual(t, commands.TwinSynchronization_DISABLED, deviceMetadataUpdated.GetTwinSynchronization().GetState()) for { deviceMetadataUpdated, err = deviceMetadataUpdatedFilter.WaitForEvent(time.Second, "") @@ -266,7 +265,7 @@ func waitForResourceChanged(filter *contentChangedFilter, ignoreHrefs ...string) return ev } for _, ignoreHref := range ignoreHrefs { - if ignoreHref == evChanged.GetResourceId().Href { + if ignoreHref == evChanged.GetResourceId().GetHref() { return waitForResourceChanged(filter, ignoreHrefs...) } } @@ -284,7 +283,7 @@ func TestRequestHandlerUpdateDeviceMetadataTwinForceSynchronization(t *testing.T defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -319,10 +318,10 @@ func TestRequestHandlerUpdateDeviceMetadataTwinForceSynchronization(t *testing.T obsDeviceMetadataUpdated, err := s.Subscribe(ctx, uuid.New().String(), utils.GetDeviceMetadataEventSubject("*", deviceID, (&events.DeviceMetadataUpdated{}).EventType()), deviceMetadataUpdatedFilter) require.NoError(t, err) defer func() { - err := obs.Close() - assert.NoError(t, err) - err = obsDeviceMetadataUpdated.Close() - assert.NoError(t, err) + errC := obs.Close() + require.NoError(t, errC) + errC = obsDeviceMetadataUpdated.Close() + require.NoError(t, errC) }() ev, err := c.UpdateDeviceMetadata(ctx, &pb.UpdateDeviceMetadataRequest{ @@ -336,7 +335,7 @@ func TestRequestHandlerUpdateDeviceMetadataTwinForceSynchronization(t *testing.T deviceMetadataUpdated, err := deviceMetadataUpdatedFilter.WaitForEvent(time.Second, ev.GetData().GetAuditContext().GetCorrelationId()) require.NoError(t, err) require.False(t, deviceMetadataUpdated.GetTwinEnabled()) - require.Equal(t, deviceMetadataUpdated.GetTwinSynchronization().GetState(), commands.TwinSynchronization_DISABLED) + require.Equal(t, commands.TwinSynchronization_DISABLED, deviceMetadataUpdated.GetTwinSynchronization().GetState()) require.Equal(t, int64(0), ev.GetData().GetTwinSynchronization().GetForceSynchronizationAt()) evResourceChanged := waitForResourceChanged(v, plgdtime.ResourceURI) @@ -355,7 +354,7 @@ func TestRequestHandlerUpdateDeviceMetadataTwinForceSynchronization(t *testing.T deviceMetadataUpdated, err = deviceMetadataUpdatedFilter.WaitForEvent(time.Second, ev.GetData().GetAuditContext().GetCorrelationId()) require.NoError(t, err) require.True(t, deviceMetadataUpdated.GetTwinEnabled()) - require.NotEqual(t, deviceMetadataUpdated.GetTwinSynchronization().GetState(), commands.TwinSynchronization_DISABLED) + require.NotEqual(t, commands.TwinSynchronization_DISABLED, deviceMetadataUpdated.GetTwinSynchronization().GetState()) require.Greater(t, ev.GetData().GetTwinSynchronization().GetForceSynchronizationAt(), checkTwin) checkTwin = ev.GetData().GetTwinSynchronization().GetForceSynchronizationAt() @@ -412,7 +411,7 @@ func TestRequestHandlerUpdateDeviceMetadataTwinForceSynchronization(t *testing.T deviceMetadataUpdated, err = deviceMetadataUpdatedFilter.WaitForEvent(time.Second, ev.GetData().GetAuditContext().GetCorrelationId()) require.NoError(t, err) require.True(t, deviceMetadataUpdated.GetTwinEnabled()) - require.NotEqual(t, deviceMetadataUpdated.GetTwinSynchronization().GetState(), commands.TwinSynchronization_DISABLED) + require.NotEqual(t, commands.TwinSynchronization_DISABLED, deviceMetadataUpdated.GetTwinSynchronization().GetState()) require.Greater(t, ev.GetData().GetTwinSynchronization().GetForceSynchronizationAt(), checkTwin) checkTwin = ev.GetData().GetTwinSynchronization().GetForceSynchronizationAt() diff --git a/grpc-gateway/service/updateResource_test.go b/grpc-gateway/service/updateResource_test.go index e8e4cf1dc..10e1f05f5 100644 --- a/grpc-gateway/service/updateResource_test.go +++ b/grpc-gateway/service/updateResource_test.go @@ -111,7 +111,7 @@ func TestUpdateResource(t *testing.T) { }, }, }, - want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), "", nil), + want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", nil), }, { name: "valid with interface", @@ -127,7 +127,7 @@ func TestUpdateResource(t *testing.T) { }, }, }, - want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), "", nil), + want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", nil), }, { name: "revert update", @@ -143,7 +143,7 @@ func TestUpdateResource(t *testing.T) { }, }, }, - want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), "", nil), + want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", nil), }, { name: "update /switches/1", @@ -170,8 +170,9 @@ func TestUpdateResource(t *testing.T) { "value": true, }), }, - Status: commands.Status_OK, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + Status: commands.Status_OK, + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: test.TestResourceSwitchesInstanceResourceTypes, }, }, } @@ -183,7 +184,7 @@ func TestUpdateResource(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -227,7 +228,7 @@ func TestRequestHandlerGetAfterUpdateResource(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -244,7 +245,7 @@ func TestRequestHandlerGetAfterUpdateResource(t *testing.T) { client, err := c.GetResources(ctx, &pb.GetResourcesRequest{ DeviceIdFilter: []string{devID}, }) - assert.NoError(t, err) + require.NoError(t, err) for { value, err := client.Recv() if errors.Is(err, io.EOF) { @@ -290,7 +291,7 @@ func TestRequestHandlerRunMultipleUpdateResource(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -307,13 +308,13 @@ func TestRequestHandlerRunMultipleUpdateResource(t *testing.T) { func() { t.Logf("TestRequestHandlerMultipleUpdateResource:run %v\n", i) lightHref := test.TestResourceLightInstanceHref("1") - ctx, cancel := context.WithTimeout(ctx, time.Second*3) + subCtx, cancel := context.WithTimeout(ctx, time.Second*3) defer cancel() - subClient, err := c.SubscribeToEvents(ctx) + subClient, err := c.SubscribeToEvents(subCtx) require.NoError(t, err) defer func() { - err = subClient.CloseSend() - require.NoError(t, err) + errC := subClient.CloseSend() + require.NoError(t, errC) }() err = subClient.Send(&pb.SubscribeToEvents{Action: &pb.SubscribeToEvents_CreateSubscription_{ @@ -329,9 +330,9 @@ func TestRequestHandlerRunMultipleUpdateResource(t *testing.T) { require.NoError(t, err) ev, err := subClient.Recv() require.NoError(t, err) - require.Equal(t, ev.GetOperationProcessed().GetErrorStatus().GetCode(), pb.Event_OperationProcessed_ErrorStatus_OK) + require.Equal(t, pb.Event_OperationProcessed_ErrorStatus_OK, ev.GetOperationProcessed().GetErrorStatus().GetCode()) for j := 1; j >= 0; j-- { - _, err = c.UpdateResource(ctx, &pb.UpdateResourceRequest{ + _, err = c.UpdateResource(subCtx, &pb.UpdateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, lightHref), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -352,7 +353,7 @@ func TestRequestHandlerRunMultipleUpdateResource(t *testing.T) { for j := 1; j >= 0; j-- { ev, err = subClient.Recv() require.NoError(t, err) - pbTest.CmpResourceChanged(t, pbTest.MakeResourceChanged(t, deviceID, lightHref, "", makeLightData(j)), ev.GetResourceChanged(), "") + pbTest.CmpResourceChanged(t, pbTest.MakeResourceChanged(t, deviceID, lightHref, test.TestResourceLightInstanceResourceTypes, "", makeLightData(j)), ev.GetResourceChanged(), "") } }() } @@ -373,7 +374,7 @@ func TestRequestHandlerRunMultipleParallelUpdateResource(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -393,10 +394,10 @@ func TestRequestHandlerRunMultipleParallelUpdateResource(t *testing.T) { go func() { defer wg.Done() lightHref := test.TestResourceLightInstanceHref("1") - ctx, cancel := context.WithTimeout(ctx, timeout) + updateCtx, cancel := context.WithTimeout(ctx, timeout) defer cancel() for j := 1; j >= 0; j-- { - _, err := c.UpdateResource(ctx, &pb.UpdateResourceRequest{ + _, err := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, lightHref), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -405,7 +406,7 @@ func TestRequestHandlerRunMultipleParallelUpdateResource(t *testing.T) { }), }, }) - require.NoError(t, err) + assert.NoError(t, err) } }() } diff --git a/grpc-gateway/subscription/subscription.go b/grpc-gateway/subscription/subscription.go index b86be8524..a830f3f22 100644 --- a/grpc-gateway/subscription/subscription.go +++ b/grpc-gateway/subscription/subscription.go @@ -1,6 +1,7 @@ package subscription import ( + "errors" "fmt" "github.com/google/uuid" @@ -129,13 +130,8 @@ func (s *Sub) Init(owner string, subCache *SubscriptionsCache) error { return nil } -func (s *Sub) isFilteredEvent(e *pb.Event, eventType FilterBitmask) (bool, error) { - if e == nil { - return false, fmt.Errorf("invalid event") - } - if !IsFilteredBit(s.filter, eventType) { - return false, nil - } +//nolint:gocyclo +func (s *Sub) isFilteredEventByType(e *pb.Event) (bool, error) { switch ev := e.GetType().(type) { case *pb.Event_DeviceRegistered_: return true, nil @@ -173,6 +169,16 @@ func (s *Sub) isFilteredEvent(e *pb.Event, eventType FilterBitmask) (bool, error return false, fmt.Errorf("unknown event type('%T')", e.GetType()) } +func (s *Sub) isFilteredEvent(e *pb.Event, eventType FilterBitmask) (bool, error) { + if e == nil { + return false, errors.New("invalid event") + } + if !IsFilteredBit(s.filter, eventType) { + return false, nil + } + return s.isFilteredEventByType(e) +} + func (s *Sub) ProcessEvent(e *pb.Event, eventType FilterBitmask) error { ok, err := s.isFilteredEvent(e, eventType) if err != nil { diff --git a/grpc-gateway/subscription/subscription_test.go b/grpc-gateway/subscription/subscription_test.go index 371360bbc..79762f6b0 100644 --- a/grpc-gateway/subscription/subscription_test.go +++ b/grpc-gateway/subscription/subscription_test.go @@ -43,7 +43,7 @@ func waitForEvent(ctx context.Context, t *testing.T, recvChan <-chan *pb.Event) func check(t *testing.T, ev *pb.Event, expectedEvent *pb.Event) { if expectedEvent.GetResourcePublished() != nil { - expectedEvent.SubscriptionId = ev.SubscriptionId + expectedEvent.SubscriptionId = ev.GetSubscriptionId() } pbTest.CmpEvent(t, expectedEvent, ev, "") } @@ -70,7 +70,7 @@ func checkAndValidateUpdate(ctx context.Context, t *testing.T, rac raservice.Res }) require.NoError(t, err) - resourceUpdatePending := pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), updCorrelationID, + resourceUpdatePending := pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, updCorrelationID, map[string]interface{}{ "power": value, }, @@ -90,7 +90,7 @@ func checkAndValidateUpdate(ctx context.Context, t *testing.T, rac raservice.Res check(t, ev, &pb.Event{ SubscriptionId: s.Id(), Type: &pb.Event_ResourceUpdated{ - ResourceUpdated: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), updCorrelationID, nil), + ResourceUpdated: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, updCorrelationID, nil), }, CorrelationId: correlationID, }) @@ -98,7 +98,7 @@ func checkAndValidateUpdate(ctx context.Context, t *testing.T, rac raservice.Res check(t, ev, &pb.Event{ SubscriptionId: s.Id(), Type: &pb.Event_ResourceChanged{ - ResourceChanged: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + ResourceChanged: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", test.LightResourceRepresentation{ Name: "Light", Power: value, @@ -126,8 +126,9 @@ func checkAndValidateRetrieve(ctx context.Context, t *testing.T, rac raservice.R SubscriptionId: s.Id(), Type: &pb.Event_ResourceRetrievePending{ ResourceRetrievePending: &events.ResourceRetrievePending{ - ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, retrieveCorrelationID, oauthService.DeviceUserID), + ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, retrieveCorrelationID, oauthService.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, }, CorrelationId: correlationID, @@ -135,7 +136,7 @@ func checkAndValidateRetrieve(ctx context.Context, t *testing.T, rac raservice.R check(t, waitForEvent(ctx, t, recvChan), &pb.Event{ SubscriptionId: s.Id(), Type: &pb.Event_ResourceRetrieved{ - ResourceRetrieved: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), + ResourceRetrieved: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, retrieveCorrelationID, test.LightResourceRepresentation{ Name: "Light", @@ -154,7 +155,7 @@ func getResourceChangedEvents(t *testing.T, deviceID, correlationID, subscriptio events[rid.GetHref()] = &pb.Event{ SubscriptionId: subscriptionID, Type: &pb.Event_ResourceChanged{ - ResourceChanged: pbTest.MakeResourceChanged(t, deviceID, rid.GetHref(), "", res.Representation), + ResourceChanged: pbTest.MakeResourceChanged(t, deviceID, rid.GetHref(), res.ResourceTypes, "", res.Representation), }, CorrelationId: correlationID, } @@ -217,8 +218,8 @@ func TestRequestHandlerSubscribeToEvents(t *testing.T) { err = s.Init(owner, subCache) require.NoError(t, err) defer func() { - err := s.Close() - require.NoError(t, err) + errC := s.Close() + require.NoError(t, errC) }() deviceID, shutdownDevSim := test.OnboardDevSim(ctx, t, rdc, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) diff --git a/grpc-gateway/subscription/subscriptionsCache.go b/grpc-gateway/subscription/subscriptionsCache.go index d0fb8c673..997fbd6f3 100644 --- a/grpc-gateway/subscription/subscriptionsCache.go +++ b/grpc-gateway/subscription/subscriptionsCache.go @@ -391,13 +391,13 @@ func (c *SubscriptionsCache) Subscribe(subject string, onEvent SendEventWithType closeFunc = c.makeCloseFunc(subject, handlerID) } if s.subscription == nil { - err := s.subscribeLocked(subject, c.conn.Subscribe, func(msg *nats.Msg) { - if err := s.handleEvent(msg); err != nil { - c.errFunc(err) + errS := s.subscribeLocked(subject, c.conn.Subscribe, func(msg *nats.Msg) { + if errH := s.handleEvent(msg); errH != nil { + c.errFunc(errH) } }) - if err != nil { - return err + if errS != nil { + return errS } } return nil diff --git a/http-gateway/Dockerfile b/http-gateway/Dockerfile index ede92cf49..ea2ea05a4 100644 --- a/http-gateway/Dockerfile +++ b/http-gateway/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM golang:1.20.13-alpine AS build +FROM golang:1.22.3-alpine AS build ARG VERSION ARG COMMIT_DATE ARG SHORT_COMMIT @@ -11,10 +11,16 @@ COPY go.mod go.sum ./ RUN go mod download COPY . . RUN go mod vendor -RUN ( cd /usr/local/go && patch -p1 < $GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch ) -RUN ( cd ./vendor/golang.org/x/oauth2 && patch -p1 < $GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/golang_org_x_oauth2_propagate_error.patch ) +WORKDIR /usr/local/go +RUN ( patch -p1 < "$GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch" ) +WORKDIR $GOPATH/src/github.com/plgd-dev/hub/vendor/golang.org/x/oauth2 +RUN ( patch -p1 < "$GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/golang_org_x_oauth2_propagate_error.patch" ) WORKDIR $GOPATH/src/github.com/plgd-dev/hub/http-gateway -RUN CGO_ENABLED=0 go build -mod=vendor -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/http-gateway ./cmd/service +RUN go build \ + -mod=vendor \ + -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o /go/bin/http-gateway \ + ./cmd/service FROM alpine:3.19 AS security-provider RUN apk add -U --no-cache ca-certificates @@ -27,4 +33,4 @@ COPY --from=security-provider /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY http-gateway/web/build /usr/local/var/www COPY --from=build /go/bin/http-gateway /usr/local/bin/http-gateway USER nonroot -ENTRYPOINT [ "/usr/local/bin/http-gateway" ] \ No newline at end of file +ENTRYPOINT [ "/usr/local/bin/http-gateway" ] diff --git a/http-gateway/Dockerfile.www b/http-gateway/Dockerfile.www index 9c97348fa..8cfa637bb 100644 --- a/http-gateway/Dockerfile.www +++ b/http-gateway/Dockerfile.www @@ -1,11 +1,11 @@ # syntax=docker/dockerfile:1 FROM node:18 AS build-web COPY http-gateway/web /web -RUN cd /web && \ - npm config set fetch-retries 3 && \ +WORKDIR /web +RUN npm config set fetch-retries 3 && \ npm config set fetch-retry-mintimeout 600000 && \ npm config set fetch-retry-maxtimeout 1200000 && \ npm config set fetch-timeout 1800000 && \ npm install --ignore-scripts && \ npm run :generate:theme && \ - npm run build \ No newline at end of file + npm run build diff --git a/http-gateway/serverMux/jsonMarshaler_test.go b/http-gateway/serverMux/jsonMarshaler_test.go index e4263e59e..567dfc578 100644 --- a/http-gateway/serverMux/jsonMarshaler_test.go +++ b/http-gateway/serverMux/jsonMarshaler_test.go @@ -27,7 +27,7 @@ func TestJsonMarshalerMarshal(t *testing.T) { { name: "valid", args: args{ - v: pb.MakeResourceChanged(t, "deviceID", "/href", "correlationID", map[interface{}]interface{}{ + v: pb.MakeResourceChanged(t, "deviceID", "/href", []string{"type"}, "correlationID", map[interface{}]interface{}{ "key": "value", }), }, @@ -44,7 +44,8 @@ func TestJsonMarshalerMarshal(t *testing.T) { "deviceId": "deviceID", "href": "/href", }, - "status": "OK", + "status": "OK", + "resourceTypes": []interface{}{"type"}, }, }, } diff --git a/http-gateway/serverMux/router.go b/http-gateway/serverMux/router.go index bd716a3e0..9c0d85a9c 100644 --- a/http-gateway/serverMux/router.go +++ b/http-gateway/serverMux/router.go @@ -14,7 +14,7 @@ import ( func NewRouter(queryCaseInsensitive map[string]string, authInterceptor kitHttp.Interceptor, opts ...kitHttp.LogOpt) *router.Router { r := router.NewRouter() r.Use(kitHttp.CreateLoggingMiddleware(opts...)) - r.Use(kitHttp.CreateAuthMiddleware(authInterceptor, func(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) { + r.Use(kitHttp.CreateAuthMiddleware(authInterceptor, func(_ context.Context, w http.ResponseWriter, r *http.Request, err error) { WriteError(w, grpc.ForwardErrorf(codes.Unauthenticated, "cannot access to %v: %w", r.RequestURI, err)) })) r.Use(kitHttp.CreateMakeQueryCaseInsensitiveMiddleware(queryCaseInsensitive, opts...)) diff --git a/http-gateway/service/cancelPendingCommands_test.go b/http-gateway/service/cancelPendingCommands_test.go index 887e20bb9..362e955f3 100644 --- a/http-gateway/service/cancelPendingCommands_test.go +++ b/http-gateway/service/cancelPendingCommands_test.go @@ -32,7 +32,7 @@ func TestRequestHandlerCancelPendingCommands(t *testing.T) { _, resourcePendings, _, shutdown := pbTest.InitPendingEvents(ctx, t) defer shutdown() - require.Equal(t, len(resourcePendings), 4) + require.Len(t, resourcePendings, 4) type args struct { deviceID string @@ -109,7 +109,7 @@ func TestRequestHandlerCancelResourceCommand(t *testing.T) { _, resourcePendings, _, shutdown := pbTest.InitPendingEvents(ctx, t) defer shutdown() - require.Equal(t, len(resourcePendings), 4) + require.Len(t, resourcePendings, 4) type args struct { deviceID string diff --git a/http-gateway/service/cancelPendingMetadataUpdate_test.go b/http-gateway/service/cancelPendingMetadataUpdate_test.go index 7caf37295..945ede80c 100644 --- a/http-gateway/service/cancelPendingMetadataUpdate_test.go +++ b/http-gateway/service/cancelPendingMetadataUpdate_test.go @@ -22,7 +22,7 @@ func TestRequestHandlerCancelDeviceMetadataUpdate(t *testing.T) { _, _, devicePendings, shutdown := pbTest.InitPendingEvents(ctx, t) defer shutdown() - require.Equal(t, len(devicePendings), 2) + require.Len(t, devicePendings, 2) type args struct { deviceID string diff --git a/http-gateway/service/cancelPendingMetadataUpdates_test.go b/http-gateway/service/cancelPendingMetadataUpdates_test.go index 4e997c275..f21bf3f13 100644 --- a/http-gateway/service/cancelPendingMetadataUpdates_test.go +++ b/http-gateway/service/cancelPendingMetadataUpdates_test.go @@ -22,7 +22,7 @@ func TestRequestHandlerCancelPendingMetadataUpdates(t *testing.T) { _, _, devicePendings, shutdown := pbTest.InitPendingEvents(ctx, t) defer shutdown() - require.Equal(t, len(devicePendings), 2) + require.Len(t, devicePendings, 2) type args struct { deviceID string diff --git a/http-gateway/service/createResource_test.go b/http-gateway/service/createResource_test.go index 404371fe3..55008bf06 100644 --- a/http-gateway/service/createResource_test.go +++ b/http-gateway/service/createResource_test.go @@ -187,7 +187,7 @@ func TestRequestHandler_CreateResource(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -219,7 +219,7 @@ func TestRequestHandler_CreateResource(t *testing.T) { return } require.NoError(t, err) - want := pbTest.MakeResourceCreated(t, deviceID, tt.args.href, "", tt.wantData) + want := pbTest.MakeResourceCreated(t, deviceID, tt.args.href, test.TestResourceSwitchesResourceTypes, "", tt.wantData) pbTest.CmpResourceCreated(t, want, got.GetData()) }) } diff --git a/http-gateway/service/deleteDevice.go b/http-gateway/service/deleteDevice.go index 48b71c444..a43eb8076 100644 --- a/http-gateway/service/deleteDevice.go +++ b/http-gateway/service/deleteDevice.go @@ -2,36 +2,19 @@ package service import ( "net/http" - "net/http/httptest" - "github.com/google/go-querystring/query" - "github.com/gorilla/mux" "github.com/plgd-dev/hub/v2/http-gateway/serverMux" - "github.com/plgd-dev/hub/v2/http-gateway/uri" kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc" "google.golang.org/grpc/codes" ) func (requestHandler *RequestHandler) deleteDevice(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - deviceID := vars[uri.DeviceIDKey] - type Options struct { - DeviceIDFilter []string `url:"deviceIdFilter"` - } - opt := Options{ - DeviceIDFilter: []string{deviceID}, - } - v, err := query.Values(opt) + deviceID, rec, err := requestHandler.serveDevicesRequest(r) if err != nil { serverMux.WriteError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "cannot delete device('%v'): %v", deviceID, err)) return } - r.URL.Path = uri.Devices - r.URL.RawQuery = v.Encode() - rec := httptest.NewRecorder() - requestHandler.mux.ServeHTTP(rec, r) - - toSimpleResponse(w, rec, func(w http.ResponseWriter, err error) { + toSimpleResponse(w, rec, false, func(w http.ResponseWriter, err error) { serverMux.WriteError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "cannot delete device('%v'): %v", deviceID, err)) }, streamResponseKey) } diff --git a/http-gateway/service/deleteDevices_test.go b/http-gateway/service/deleteDevices_test.go index 3a5ab5309..2ebb1bb9d 100644 --- a/http-gateway/service/deleteDevices_test.go +++ b/http-gateway/service/deleteDevices_test.go @@ -34,7 +34,7 @@ func TestRequestHandlerDeleteDevices(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -93,7 +93,7 @@ func TestRequestHandlerDeleteDevices(t *testing.T) { var got pb.DeleteDevicesResponse err = httpgwTest.Unmarshal(resp.StatusCode, resp.Body, &got) require.NoError(t, err) - require.Equal(t, tt.want.DeviceIds, got.DeviceIds) + require.Equal(t, tt.want.GetDeviceIds(), got.GetDeviceIds()) }) } } diff --git a/http-gateway/service/deleteResource_test.go b/http-gateway/service/deleteResource_test.go index 1b832a95b..95742cae3 100644 --- a/http-gateway/service/deleteResource_test.go +++ b/http-gateway/service/deleteResource_test.go @@ -119,7 +119,7 @@ func TestRequestHandlerDeleteResource(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -149,7 +149,7 @@ func TestRequestHandlerDeleteResource(t *testing.T) { return } require.NoError(t, err) - want := pbTest.MakeResourceDeleted(deviceID, tt.args.href, "") + want := pbTest.MakeResourceDeleted(deviceID, tt.args.href, test.TestResourceSwitchesInstanceResourceTypes, "") pbTest.CmpResourceDeleted(t, want, got.GetData()) }) } @@ -198,7 +198,7 @@ func TestRequestHandlerBatchDeleteResource(t *testing.T) { href: test.TestResourceSwitchesHref, }, want: func() *events.ResourceDeleted { - rdel := pbTest.MakeResourceDeleted(deviceID, test.TestResourceSwitchesHref, "") + rdel := pbTest.MakeResourceDeleted(deviceID, test.TestResourceSwitchesHref, test.TestResourceSwitchesResourceTypes, "") links := test.CollectionLinkRepresentations{} for _, switchID := range switchIDs { links = append(links, test.CollectionLinkRepresentation{ @@ -229,7 +229,7 @@ func TestRequestHandlerBatchDeleteResource(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/http-gateway/service/getDevice.go b/http-gateway/service/getDevice.go index 0cf9e3985..8a3eac3c7 100644 --- a/http-gateway/service/getDevice.go +++ b/http-gateway/service/getDevice.go @@ -25,7 +25,8 @@ func isNotModifiedResponse(result interface{}) bool { } data, ok := m["data"] if ok { - tmp, ok := data.(map[string]interface{}) + var tmp map[string]interface{} + tmp, ok = data.(map[string]interface{}) if !ok { return false } @@ -64,7 +65,10 @@ func writeSimpleResponse(w http.ResponseWriter, rec *httptest.ResponseRecorder, } } -func toSimpleResponse(w http.ResponseWriter, rec *httptest.ResponseRecorder, writeError func(w http.ResponseWriter, err error), responseKeys ...string) { +func getResponse(rec *httptest.ResponseRecorder, allowEmpty bool, responseKeys ...string) (interface{}, error) { + if len(rec.Body.Bytes()) == 0 && allowEmpty { + return nil, nil + } iter := json.NewDecoder(bytes.NewReader(rec.Body.Bytes())) datas := make([]interface{}, 0, 1) for { @@ -74,21 +78,17 @@ func toSimpleResponse(w http.ResponseWriter, rec *httptest.ResponseRecorder, wri break } if err != nil { - writeError(w, err) - return + return nil, err } datas = append(datas, v) } if len(datas) == 0 { - writeError(w, kitNetGrpc.ForwardErrorf(codes.NotFound, "not found")) - return + return nil, kitNetGrpc.ForwardErrorf(codes.NotFound, "not found") } if len(datas) != 1 { - writeError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "invalid number of responses")) - return + return nil, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "invalid number of responses") } - var result interface{} - result = datas[0] + result := datas[0] for _, key := range responseKeys { m, ok := result.(map[string]interface{}) if !ok { @@ -101,10 +101,19 @@ func toSimpleResponse(w http.ResponseWriter, rec *httptest.ResponseRecorder, wri break } } + return result, nil +} + +func toSimpleResponse(w http.ResponseWriter, rec *httptest.ResponseRecorder, allowEmpty bool, writeError func(w http.ResponseWriter, err error), responseKeys ...string) { + result, err := getResponse(rec, allowEmpty, responseKeys...) + if err != nil { + writeError(w, err) + return + } writeSimpleResponse(w, rec, result, writeError) } -func (requestHandler *RequestHandler) getDevice(w http.ResponseWriter, r *http.Request) { +func (requestHandler *RequestHandler) serveDevicesRequest(r *http.Request) (string, *httptest.ResponseRecorder, error) { vars := mux.Vars(r) deviceID := vars[uri.DeviceIDKey] type Options struct { @@ -115,15 +124,22 @@ func (requestHandler *RequestHandler) getDevice(w http.ResponseWriter, r *http.R } v, err := query.Values(opt) if err != nil { - serverMux.WriteError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "cannot get device('%v'): %v", deviceID, err)) - return + return deviceID, nil, err } r.URL.Path = uri.Devices r.URL.RawQuery = v.Encode() rec := httptest.NewRecorder() requestHandler.mux.ServeHTTP(rec, r) + return deviceID, rec, nil +} - toSimpleResponse(w, rec, func(w http.ResponseWriter, err error) { +func (requestHandler *RequestHandler) getDevice(w http.ResponseWriter, r *http.Request) { + deviceID, rec, err := requestHandler.serveDevicesRequest(r) + if err != nil { + serverMux.WriteError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "cannot get device('%v'): %v", deviceID, err)) + return + } + toSimpleResponse(w, rec, false, func(w http.ResponseWriter, err error) { serverMux.WriteError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "cannot get device('%v'): %v", deviceID, err)) }, streamResponseKey) } diff --git a/http-gateway/service/getDevicePendingCommands_test.go b/http-gateway/service/getDevicePendingCommands_test.go index 1f6d5281e..af60afb90 100644 --- a/http-gateway/service/getDevicePendingCommands_test.go +++ b/http-gateway/service/getDevicePendingCommands_test.go @@ -63,13 +63,14 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { DeviceId: deviceID, Href: platform.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: []string{platform.ResourceType}, }, }, }, { Command: &pb.PendingCommand_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -82,13 +83,14 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, { Command: &pb.PendingCommand_ResourceUpdatePending{ - ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -111,7 +113,8 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { DeviceId: deviceID, Href: platform.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: []string{platform.ResourceType}, }, }, }, @@ -127,7 +130,7 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "power": 1, }, @@ -151,7 +154,8 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -167,7 +171,7 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceUpdatePending{ - ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -185,7 +189,7 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -198,7 +202,8 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -231,7 +236,7 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -246,9 +251,9 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { secureGWShutdown() createFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + createCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.CreateResource(ctx, &pb.CreateResourceRequest{ + _, errC := c.CreateResource(createCtx, &pb.CreateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -257,22 +262,22 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { }), }, }) - require.Error(t, err) + require.Error(t, errC) } createFn() retrieveFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + retrieveCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.GetResourceFromDevice(ctx, &pb.GetResourceFromDeviceRequest{ + _, errG := c.GetResourceFromDevice(retrieveCtx, &pb.GetResourceFromDeviceRequest{ ResourceId: commands.NewResourceID(deviceID, platform.ResourceURI), }) - require.Error(t, err) + require.Error(t, errG) } retrieveFn() updateFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateResource(ctx, &pb.UpdateResourceRequest{ + _, errU := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -281,26 +286,26 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) { }), }, }) - require.Error(t, err) + require.Error(t, errU) } updateFn() deleteFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + deleteCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.DeleteResource(ctx, &pb.DeleteResourceRequest{ + _, errD := c.DeleteResource(deleteCtx, &pb.DeleteResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), }) - require.Error(t, err) + require.Error(t, errD) } deleteFn() updateDeviceMetadataFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateDeviceMetadata(ctx, &pb.UpdateDeviceMetadataRequest{ + _, errU := c.UpdateDeviceMetadata(updateCtx, &pb.UpdateDeviceMetadataRequest{ DeviceId: deviceID, TwinEnabled: false, }) - require.Error(t, err) + require.Error(t, errU) } updateDeviceMetadataFn() diff --git a/http-gateway/service/getDeviceResourceLinks.go b/http-gateway/service/getDeviceResourceLinks.go index bc9c865b8..7eb6b3d90 100644 --- a/http-gateway/service/getDeviceResourceLinks.go +++ b/http-gateway/service/getDeviceResourceLinks.go @@ -40,7 +40,7 @@ func (requestHandler *RequestHandler) getDeviceResourceLinks(w http.ResponseWrit rec := httptest.NewRecorder() requestHandler.mux.ServeHTTP(rec, r) - toSimpleResponse(w, rec, func(w http.ResponseWriter, err error) { + toSimpleResponse(w, rec, false, func(w http.ResponseWriter, err error) { serverMux.WriteError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "cannot get device('%v') resource links: %v", deviceID, err)) }, streamResponseKey) } diff --git a/http-gateway/service/getDeviceResourceLinks_test.go b/http-gateway/service/getDeviceResourceLinks_test.go index bd5549d93..889ddcd9b 100644 --- a/http-gateway/service/getDeviceResourceLinks_test.go +++ b/http-gateway/service/getDeviceResourceLinks_test.go @@ -41,7 +41,7 @@ func TestRequestHandlerGetDeviceResourceLinks(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/http-gateway/service/getDeviceResources_test.go b/http-gateway/service/getDeviceResources_test.go index 7cecbea5e..284c2d396 100644 --- a/http-gateway/service/getDeviceResources_test.go +++ b/http-gateway/service/getDeviceResources_test.go @@ -34,7 +34,7 @@ func getResourceChanged(t *testing.T, deviceID string, href string) *events.Reso for _, l := range test.GetAllBackendResourceRepresentations(t, deviceID, test.TestDeviceName) { rid := commands.ResourceIdFromString(l.Href) if rid.GetHref() == href { - return pbTest.MakeResourceChanged(t, deviceID, rid.GetHref(), "", l.Representation) + return pbTest.MakeResourceChanged(t, deviceID, rid.GetHref(), l.ResourceTypes, "", l.Representation) } } return nil @@ -65,7 +65,7 @@ func getResources(t *testing.T, deviceID, deviceName, switchID string) []*pb.Res if rid.GetHref() == test.TestResourceSwitchesHref { resources = append(resources, &pb.Resource{ Types: getResourceType(rid.GetHref()), - Data: pbTest.MakeResourceChanged(t, deviceID, rid.GetHref(), "", []interface{}{ + Data: pbTest.MakeResourceChanged(t, deviceID, rid.GetHref(), res.ResourceTypes, "", []interface{}{ map[string]interface{}{ "href": test.TestResourceSwitchesInstanceHref(switchID), "if": []string{interfaces.OC_IF_A, interfaces.OC_IF_BASELINE}, @@ -80,13 +80,13 @@ func getResources(t *testing.T, deviceID, deviceName, switchID string) []*pb.Res } else { resources = append(resources, &pb.Resource{ Types: getResourceType(rid.GetHref()), - Data: pbTest.MakeResourceChanged(t, deviceID, rid.GetHref(), "", res.Representation), + Data: pbTest.MakeResourceChanged(t, deviceID, rid.GetHref(), res.ResourceTypes, "", res.Representation), }) } } resources = append(resources, &pb.Resource{ Types: []string{types.BINARY_SWITCH}, - Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), "", test.SwitchResourceRepresentation{}), + Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), test.TestResourceSwitchesInstanceResourceTypes, "", test.SwitchResourceRepresentation{}), }) return resources } @@ -154,7 +154,7 @@ func TestRequestHandlerGetDeviceResources(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) defer func() { diff --git a/http-gateway/service/getDevice_test.go b/http-gateway/service/getDevice_test.go index 3e3c09c98..e3390aeb5 100644 --- a/http-gateway/service/getDevice_test.go +++ b/http-gateway/service/getDevice_test.go @@ -68,7 +68,7 @@ func TestRequestHandlerGetDevice(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -101,7 +101,7 @@ func TestRequestHandlerGetDevice(t *testing.T) { return } require.NoError(t, err) - assert.NotEmpty(t, dev.ProtocolIndependentId) + assert.NotEmpty(t, dev.GetProtocolIndependentId()) devices = append(devices, &dev) } pbTest.CmpDeviceValues(t, tt.want, devices) diff --git a/http-gateway/service/getDevicesMetadata_test.go b/http-gateway/service/getDevicesMetadata_test.go index 8e542ec94..4ffc9668d 100644 --- a/http-gateway/service/getDevicesMetadata_test.go +++ b/http-gateway/service/getDevicesMetadata_test.go @@ -121,7 +121,7 @@ func TestRequestHandlerGetDevicesMetadata(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/http-gateway/service/getDevices_test.go b/http-gateway/service/getDevices_test.go index db6db4416..b7604c9ed 100644 --- a/http-gateway/service/getDevices_test.go +++ b/http-gateway/service/getDevices_test.go @@ -121,7 +121,7 @@ func TestRequestHandlerGetDevices(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) defer func() { @@ -134,7 +134,7 @@ func TestRequestHandlerGetDevices(t *testing.T) { defer shutdownDevSim() toStringSlice := func(s []pb.GetDevicesRequest_Status) []string { - var sf []string + sf := make([]string, 0, len(s)) for _, v := range s { sf = append(sf, strconv.FormatInt(int64(v), 10)) } @@ -158,7 +158,7 @@ func TestRequestHandlerGetDevices(t *testing.T) { break } require.NoError(t, err) - assert.NotEmpty(t, dev.ProtocolIndependentId) + assert.NotEmpty(t, dev.GetProtocolIndependentId()) devices = append(devices, &dev) } pbTest.CmpDeviceValues(t, tt.want, devices) diff --git a/http-gateway/service/getEvents_test.go b/http-gateway/service/getEvents_test.go index ae72ae375..9cec4e49d 100644 --- a/http-gateway/service/getEvents_test.go +++ b/http-gateway/service/getEvents_test.go @@ -56,7 +56,7 @@ func TestRequestHandlerGetEvents(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/http-gateway/service/getHubConfiguration.go b/http-gateway/service/getHubConfiguration.go index f63659c77..4bfb2e90f 100644 --- a/http-gateway/service/getHubConfiguration.go +++ b/http-gateway/service/getHubConfiguration.go @@ -78,7 +78,7 @@ func (requestHandler *RequestHandler) getHubConfiguration(w http.ResponseWriter, m := serverMux.NewJsonpbMarshaler() w.Header().Set(contentTypeHeaderKey, uri.ApplicationProtoJsonContentType) w.WriteHeader(http.StatusOK) - if err := m.NewEncoder(w).Encode(resp); err != nil { + if err = m.NewEncoder(w).Encode(resp); err != nil { log.Errorf("failed to write response: %v", err) } return diff --git a/http-gateway/service/getPendingCommands_test.go b/http-gateway/service/getPendingCommands_test.go index 9813962c4..3682ba020 100644 --- a/http-gateway/service/getPendingCommands_test.go +++ b/http-gateway/service/getPendingCommands_test.go @@ -63,7 +63,7 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceUpdatePending{ - ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -96,13 +96,14 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { DeviceId: deviceID, Href: platform.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: []string{platform.ResourceType}, }, }, }, { Command: &pb.PendingCommand_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -115,13 +116,14 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, { Command: &pb.PendingCommand_ResourceUpdatePending{ - ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -143,7 +145,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { DeviceId: deviceID, Href: platform.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: []string{platform.ResourceType}, }, }, }, @@ -158,7 +161,7 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -180,7 +183,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -195,7 +199,7 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceUpdatePending{ - ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -212,7 +216,7 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -225,7 +229,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -278,7 +283,7 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -293,9 +298,9 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { secureGWShutdown() createFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + createCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.CreateResource(ctx, &pb.CreateResourceRequest{ + _, errC := c.CreateResource(createCtx, &pb.CreateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -304,22 +309,22 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { }), }, }) - require.Error(t, err) + require.Error(t, errC) } createFn() retrieveFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + retrieveCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.GetResourceFromDevice(ctx, &pb.GetResourceFromDeviceRequest{ + _, errG := c.GetResourceFromDevice(retrieveCtx, &pb.GetResourceFromDeviceRequest{ ResourceId: commands.NewResourceID(deviceID, platform.ResourceURI), }) - require.Error(t, err) + require.Error(t, errG) } retrieveFn() updateFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateResource(ctx, &pb.UpdateResourceRequest{ + _, errU := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -328,26 +333,26 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { }), }, }) - require.Error(t, err) + require.Error(t, errU) } updateFn() deleteFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + deleteCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.DeleteResource(ctx, &pb.DeleteResourceRequest{ + _, errD := c.DeleteResource(deleteCtx, &pb.DeleteResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), }) - require.Error(t, err) + require.Error(t, errD) } deleteFn() updateDeviceMetadataFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateDeviceMetadata(ctx, &pb.UpdateDeviceMetadataRequest{ + _, errU := c.UpdateDeviceMetadata(updateCtx, &pb.UpdateDeviceMetadataRequest{ DeviceId: deviceID, TwinEnabled: false, }) - require.Error(t, err) + require.Error(t, errU) } updateDeviceMetadataFn() diff --git a/http-gateway/service/getPendingMetadataUpdates_test.go b/http-gateway/service/getPendingMetadataUpdates_test.go index 263a3d1ea..622861bb7 100644 --- a/http-gateway/service/getPendingMetadataUpdates_test.go +++ b/http-gateway/service/getPendingMetadataUpdates_test.go @@ -93,7 +93,7 @@ func TestRequestHandlerGetPendingMetadataUpdates(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -108,9 +108,9 @@ func TestRequestHandlerGetPendingMetadataUpdates(t *testing.T) { secureGWShutdown() createFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + createCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.CreateResource(ctx, &pb.CreateResourceRequest{ + _, errC := c.CreateResource(createCtx, &pb.CreateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -119,22 +119,22 @@ func TestRequestHandlerGetPendingMetadataUpdates(t *testing.T) { }), }, }) - require.Error(t, err) + require.Error(t, errC) } createFn() retrieveFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + retrieveCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.GetResourceFromDevice(ctx, &pb.GetResourceFromDeviceRequest{ + _, errG := c.GetResourceFromDevice(retrieveCtx, &pb.GetResourceFromDeviceRequest{ ResourceId: commands.NewResourceID(deviceID, platform.ResourceURI), }) - require.Error(t, err) + require.Error(t, errG) } retrieveFn() updateFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateResource(ctx, &pb.UpdateResourceRequest{ + _, errU := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -143,26 +143,26 @@ func TestRequestHandlerGetPendingMetadataUpdates(t *testing.T) { }), }, }) - require.Error(t, err) + require.Error(t, errU) } updateFn() deleteFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + deleteCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.DeleteResource(ctx, &pb.DeleteResourceRequest{ + _, errD := c.DeleteResource(deleteCtx, &pb.DeleteResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), }) - require.Error(t, err) + require.Error(t, errD) } deleteFn() updateDeviceMetadataFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateDeviceMetadata(ctx, &pb.UpdateDeviceMetadataRequest{ + _, errU := c.UpdateDeviceMetadata(updateCtx, &pb.UpdateDeviceMetadataRequest{ DeviceId: deviceID, TwinEnabled: false, }) - require.Error(t, err) + require.Error(t, errU) } updateDeviceMetadataFn() diff --git a/http-gateway/service/getResource.go b/http-gateway/service/getResource.go index 1f0272cd6..9f8db8a07 100644 --- a/http-gateway/service/getResource.go +++ b/http-gateway/service/getResource.go @@ -2,18 +2,22 @@ package service import ( "encoding/base64" + "fmt" "net/http" "net/http/httptest" + "strconv" "strings" "github.com/google/go-querystring/query" "github.com/gorilla/mux" + "github.com/plgd-dev/device/v2/pkg/codec/json" "github.com/plgd-dev/hub/v2/grpc-gateway/pb" "github.com/plgd-dev/hub/v2/http-gateway/serverMux" "github.com/plgd-dev/hub/v2/http-gateway/uri" kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc" "github.com/plgd-dev/hub/v2/resource-aggregate/commands" "google.golang.org/grpc/codes" + "google.golang.org/protobuf/encoding/protojson" ) const errFmtFromTwin = "cannot get resource('%v') from twin: %w" @@ -47,7 +51,7 @@ func getETags(r *http.Request) [][]byte { return etags } -func (requestHandler *RequestHandler) getResourceFromTwin(w http.ResponseWriter, r *http.Request, resourceID *pb.ResourceIdFilter) { +func (requestHandler *RequestHandler) getResourceFromTwin(r *http.Request, resourceID *pb.ResourceIdFilter) (*httptest.ResponseRecorder, error) { type Options struct { ResourceIDFilter []string `url:"httpResourceIdFilter"` } @@ -57,33 +61,35 @@ func (requestHandler *RequestHandler) getResourceFromTwin(w http.ResponseWriter, v, err := query.Values(opt) if err != nil { - serverMux.WriteError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, errFmtFromTwin, resourceID, err)) - return + return nil, err } r.URL.Path = uri.Resources r.URL.RawQuery = v.Encode() rec := httptest.NewRecorder() requestHandler.mux.ServeHTTP(rec, r) + return rec, nil +} - toSimpleResponse(w, rec, func(w http.ResponseWriter, err error) { - serverMux.WriteError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, errFmtFromTwin, resourceID, err)) - }, streamResponseKey) +func parseBoolQuery(str string) bool { + val, err := strconv.ParseBool(str) + if err != nil { + return false + } + return val } -func (requestHandler *RequestHandler) getResource(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - deviceID := vars[uri.DeviceIDKey] - resourceHref := vars[uri.ResourceHrefKey] - twin := r.URL.Query().Get(uri.TwinQueryKey) - resourceInterface := r.URL.Query().Get(uri.ResourceInterfaceQueryKey) +func (requestHandler *RequestHandler) serveResourceRequest(r *http.Request, deviceID, resourceHref, twin, resourceInterface string) (*httptest.ResponseRecorder, bool, error) { resourceID := pb.ResourceIdFilter{ ResourceId: commands.NewResourceID(deviceID, resourceHref), Etag: getETags(r), } - if (twin == "" || strings.ToLower(twin) == "true") && resourceInterface == "" { - requestHandler.getResourceFromTwin(w, r, &resourceID) - return + if (twin == "" || parseBoolQuery(twin)) && resourceInterface == "" { + rec, err := requestHandler.getResourceFromTwin(r, &resourceID) + if err != nil { + return nil, false, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, errFmtFromTwin, &resourceID, err) + } + return rec, true, nil } query := r.URL.Query() @@ -97,7 +103,91 @@ func (requestHandler *RequestHandler) getResource(w http.ResponseWriter, r *http rec := httptest.NewRecorder() requestHandler.mux.ServeHTTP(rec, r) - toSimpleResponse(w, rec, func(w http.ResponseWriter, err error) { - serverMux.WriteError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "cannot get resource('%v') from the device: %v", resourceID.ToString(), err)) - }) + return rec, false, nil +} + +func jsonGetValueOnPath(v interface{}, path ...string) (interface{}, error) { + for idx, p := range path { + if v == nil { + return nil, fmt.Errorf("doesn't contains %v", strings.Join(path[:idx+1], ".")) + } + m, ok := v.(map[interface{}]interface{}) + if !ok { + return nil, fmt.Errorf("%v is not a map but %T", strings.Join(path[:idx+1], "."), v) + } + v, ok = m[p] + if !ok { + return nil, fmt.Errorf("doesn't contains %v", strings.Join(path[:idx+1], ".")) + } + } + return v, nil +} + +func isContentEmpty(data []byte) bool { + if len(data) == 0 { + return true + } + var ct commands.Content + err := protojson.Unmarshal(data, &ct) + if err != nil { + return false + } + return len(ct.GetData()) == 0 && ct.GetCoapContentFormat() == -1 +} + +func (requestHandler *RequestHandler) filterOnlyContent(rec *httptest.ResponseRecorder, contentPath ...string) (resetContent bool) { + if rec.Code == http.StatusNotModified { + rec.Body.Reset() + return false + } + if rec.Code != http.StatusOK { + return false + } + var v map[interface{}]interface{} + err := json.Decode(rec.Body.Bytes(), &v) + if err != nil { + requestHandler.logger.Debugf("filter only content: cannot decode response : %v", err) + return false + } + content, err := jsonGetValueOnPath(v, contentPath...) + if err != nil { + requestHandler.logger.With("body", v).Debugf("filter only content: %v", err) + return false + } + body, err := json.Encode(content) + if err != nil { + requestHandler.logger.With("body", v).Debugf("filter only content: cannot encode 'content' object: %v", err) + return false + } + rec.Body.Reset() + if !isContentEmpty(body) { + _, _ = rec.Body.Write(body) + return false + } + return true +} + +func (requestHandler *RequestHandler) getResource(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + deviceID := vars[uri.DeviceIDKey] + resourceHref := vars[uri.ResourceHrefKey] + twin := r.URL.Query().Get(uri.TwinQueryKey) + onlyContent := r.URL.Query().Get(uri.OnlyContentQueryKey) + resourceInterface := r.URL.Query().Get(uri.ResourceInterfaceQueryKey) + rec, fromTwin, err := requestHandler.serveResourceRequest(r, deviceID, resourceHref, twin, resourceInterface) + if err != nil { + serverMux.WriteError(w, err) + return + } + allowEmptyContent := false + if parseBoolQuery(onlyContent) { + filterPath := []string{"result", "data", "content"} + if !fromTwin { + filterPath = []string{"data", "content"} + } + allowEmptyContent = requestHandler.filterOnlyContent(rec, filterPath...) + } + toSimpleResponse(w, rec, allowEmptyContent, func(w http.ResponseWriter, err error) { + serverMux.WriteError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "cannot get resource('%v/%v') from the device: %v", deviceID, resourceHref, err)) + }, streamResponseKey) } diff --git a/http-gateway/service/getResourceLinks_test.go b/http-gateway/service/getResourceLinks_test.go index 49d301598..053984318 100644 --- a/http-gateway/service/getResourceLinks_test.go +++ b/http-gateway/service/getResourceLinks_test.go @@ -40,7 +40,7 @@ func TestRequestHandlerGetResourceLinks(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) defer func() { diff --git a/http-gateway/service/getResourcePendingCommands_test.go b/http-gateway/service/getResourcePendingCommands_test.go index b06eb5d70..885a82939 100644 --- a/http-gateway/service/getResourcePendingCommands_test.go +++ b/http-gateway/service/getResourcePendingCommands_test.go @@ -59,7 +59,7 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -72,7 +72,8 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -89,7 +90,7 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) { want: []*pb.PendingCommand{ { Command: &pb.PendingCommand_ResourceCreatePending{ - ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, "", + ResourceCreatePending: pbTest.MakeResourceCreatePending(t, deviceID, device.ResourceURI, test.TestResourceDeviceResourceTypes, "", map[string]interface{}{ "power": 1, }), @@ -113,7 +114,8 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -146,7 +148,7 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -161,9 +163,9 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) { secureGWShutdown() createFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + createCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.CreateResource(ctx, &pb.CreateResourceRequest{ + _, errC := c.CreateResource(createCtx, &pb.CreateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -172,22 +174,22 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) { }), }, }) - require.Error(t, err) + require.Error(t, errC) } createFn() retrieveFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + retrieveCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.GetResourceFromDevice(ctx, &pb.GetResourceFromDeviceRequest{ + _, errG := c.GetResourceFromDevice(retrieveCtx, &pb.GetResourceFromDeviceRequest{ ResourceId: commands.NewResourceID(deviceID, platform.ResourceURI), }) - require.Error(t, err) + require.Error(t, errG) } retrieveFn() updateFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateResource(ctx, &pb.UpdateResourceRequest{ + _, errU := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -196,26 +198,26 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) { }), }, }) - require.Error(t, err) + require.Error(t, errU) } updateFn() deleteFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + deleteCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.DeleteResource(ctx, &pb.DeleteResourceRequest{ + _, errD := c.DeleteResource(deleteCtx, &pb.DeleteResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), }) - require.Error(t, err) + require.Error(t, errD) } deleteFn() updateDeviceMetadataFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + deleteCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateDeviceMetadata(ctx, &pb.UpdateDeviceMetadataRequest{ + _, errU := c.UpdateDeviceMetadata(deleteCtx, &pb.UpdateDeviceMetadataRequest{ DeviceId: deviceID, TwinEnabled: false, }) - require.Error(t, err) + require.Error(t, errU) } updateDeviceMetadataFn() diff --git a/http-gateway/service/getResource_test.go b/http-gateway/service/getResource_test.go index 7512db5f1..cc2fa9006 100644 --- a/http-gateway/service/getResource_test.go +++ b/http-gateway/service/getResource_test.go @@ -9,6 +9,7 @@ import ( "net/http" "testing" + "github.com/plgd-dev/device/v2/pkg/codec/json" "github.com/plgd-dev/device/v2/schema/interfaces" "github.com/plgd-dev/device/v2/test/resource/types" "github.com/plgd-dev/hub/v2/grpc-gateway/pb" @@ -47,7 +48,7 @@ func TestRequestHandlerGetResource(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -91,9 +92,10 @@ func TestRequestHandlerGetResource(t *testing.T) { DeviceId: deviceID, Href: test.TestResourceLightInstanceHref("1"), }, - Status: commands.Status_OK, - Content: &commands.Content{}, // content is encoded as json - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + Status: commands.Status_OK, + Content: &commands.Content{}, // content is encoded as json + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, wantCode: http.StatusOK, }, @@ -104,7 +106,7 @@ func TestRequestHandlerGetResource(t *testing.T) { deviceID: deviceID, resourceHref: test.TestResourceLightInstanceHref("1"), }, - want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "state": false, "power": uint64(0), @@ -152,7 +154,7 @@ func TestRequestHandlerGetResource(t *testing.T) { resourceHref: test.TestResourceLightInstanceHref("1"), resourceInterface: interfaces.OC_IF_BASELINE, }, - want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "state": false, "power": uint64(0), @@ -171,7 +173,7 @@ func TestRequestHandlerGetResource(t *testing.T) { resourceHref: test.TestResourceLightInstanceHref("1"), twin: newBool(false), }, - want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + want: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "state": false, "power": uint64(0), @@ -206,7 +208,7 @@ func TestRequestHandlerGetResource(t *testing.T) { values = append(values, value.GetData()) } if tt.wantCode != http.StatusOK { - require.Len(t, values, 0) + require.Empty(t, values) return } require.Len(t, values, 1) @@ -214,3 +216,94 @@ func TestRequestHandlerGetResource(t *testing.T) { }) } } + +func TestRequestHandlerGetResourceWithOnlyContent(t *testing.T) { + deviceID := test.MustFindDeviceByName(test.TestDeviceName) + + ctx, cancel := context.WithTimeout(context.Background(), config.TEST_TIMEOUT) + defer cancel() + + tearDown := service.SetUp(ctx, t) + defer tearDown() + + shutdownHttp := httpgwTest.SetUp(t) + defer shutdownHttp() + + token := oauthTest.GetDefaultAccessToken(t) + ctx = kitNetGrpc.CtxWithToken(ctx, token) + + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + RootCAs: test.GetRootCertificatePool(t), + }))) + require.NoError(t, err) + defer func() { + _ = conn.Close() + }() + c := pb.NewGrpcGatewayClient(conn) + + _, shutdownDevSim := test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) + defer shutdownDevSim() + + type args struct { + deviceID string + resourceHref string + twin *bool + } + tests := []struct { + name string + args args + want interface{} + wantCode int + }{ + { + name: "json: get resource from twin", + args: args{ + deviceID: deviceID, + resourceHref: test.TestResourceLightInstanceHref("1"), + }, + want: map[interface{}]interface{}{"name": "Light", "power": uint64(0x0), "state": false}, + wantCode: http.StatusOK, + }, + { + name: "json: get resource from device", + args: args{ + deviceID: deviceID, + resourceHref: test.TestResourceLightInstanceHref("1"), + twin: newBool(false), + }, + want: map[interface{}]interface{}{"name": "Light", "power": uint64(0x0), "state": false}, + wantCode: http.StatusOK, + }, + { + name: "json: not exists", + args: args{ + deviceID: deviceID, + resourceHref: "/not-exists", + }, + wantCode: http.StatusNotFound, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rb := httpgwTest.NewRequest(http.MethodGet, uri.AliasDeviceResource, nil).AuthToken(token) + rb.DeviceId(tt.args.deviceID).ResourceHref(tt.args.resourceHref) + rb.OnlyContent(true) + if tt.args.twin != nil { + rb.Twin(*tt.args.twin) + } + resp := httpgwTest.HTTPDo(t, rb.Build()) + defer func() { + _ = resp.Body.Close() + }() + require.Equal(t, tt.wantCode, resp.StatusCode) + if tt.wantCode != http.StatusOK { + return + } + var got interface{} + err := json.ReadFrom(resp.Body, &got) + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} diff --git a/http-gateway/service/getResources_test.go b/http-gateway/service/getResources_test.go index 0d1544a0b..e2206e5c3 100644 --- a/http-gateway/service/getResources_test.go +++ b/http-gateway/service/getResources_test.go @@ -47,7 +47,7 @@ func TestRequestHandlerGetResources(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -128,7 +128,7 @@ func TestRequestHandlerGetResources(t *testing.T) { want: []*pb.Resource{ { Types: []string{types.CORE_LIGHT}, - Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "state": false, "power": uint64(0), @@ -147,7 +147,7 @@ func TestRequestHandlerGetResources(t *testing.T) { want: []*pb.Resource{ { Types: []string{types.BINARY_SWITCH}, - Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), "", + Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceSwitchesInstanceHref(switchID), test.TestResourceSwitchesInstanceResourceTypes, "", map[string]interface{}{ "value": false, }, @@ -178,7 +178,8 @@ func TestRequestHandlerGetResources(t *testing.T) { Content: &commands.Content{ CoapContentFormat: -1, }, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, }, }, @@ -206,7 +207,8 @@ func TestRequestHandlerGetResources(t *testing.T) { Content: &commands.Content{ CoapContentFormat: -1, }, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, }, }, diff --git a/http-gateway/service/getThings.go b/http-gateway/service/getThings.go new file mode 100644 index 000000000..56b09aee6 --- /dev/null +++ b/http-gateway/service/getThings.go @@ -0,0 +1,392 @@ +package service + +import ( + "context" + "errors" + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/url" + + "github.com/google/uuid" + "github.com/gorilla/mux" + jsoniter "github.com/json-iterator/go" + bridgeDeviceTD "github.com/plgd-dev/device/v2/bridge/device/thingDescription" + "github.com/plgd-dev/device/v2/bridge/resources" + bridgeResourcesTD "github.com/plgd-dev/device/v2/bridge/resources/thingDescription" + schemaCloud "github.com/plgd-dev/device/v2/schema/cloud" + schemaCredential "github.com/plgd-dev/device/v2/schema/credential" + schemaDevice "github.com/plgd-dev/device/v2/schema/device" + schemaMaintenance "github.com/plgd-dev/device/v2/schema/maintenance" + "github.com/plgd-dev/go-coap/v3/message" + "github.com/plgd-dev/hub/v2/grpc-gateway/pb" + "github.com/plgd-dev/hub/v2/http-gateway/serverMux" + "github.com/plgd-dev/hub/v2/http-gateway/uri" + "github.com/plgd-dev/hub/v2/pkg/log" + kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc" + "github.com/plgd-dev/hub/v2/pkg/security/openid" + "github.com/plgd-dev/hub/v2/resource-aggregate/events" + wotTD "github.com/web-of-things-open-source/thingdescription-go/thingDescription" + "google.golang.org/grpc/codes" +) + +type ThingLink struct { + Href string `json:"href"` + Rel string `json:"rel"` +} + +type GetThingsResponse struct { + Base string `json:"base"` + Security *wotTD.TypeDeclaration `json:"security"` + ID string `json:"id"` + SecurityDefinitions map[string]wotTD.SecurityScheme `json:"securityDefinitions"` + Links []ThingLink `json:"links"` +} + +const ( + ThingLinkRelationItem = "item" + ThingLinkRelationCollection = "collection" +) + +func (requestHandler *RequestHandler) getResourceLinks(ctx context.Context, deviceFilter []string, typeFilter []string) ([]*events.ResourceLinksPublished, error) { + client, err := requestHandler.client.GrpcGatewayClient().GetResourceLinks(ctx, &pb.GetResourceLinksRequest{ + DeviceIdFilter: deviceFilter, + TypeFilter: typeFilter, + }) + if err != nil { + return nil, fmt.Errorf("cannot get resource links: %w", err) + } + links := make([]*events.ResourceLinksPublished, 0, 16) + for { + link, err := client.Recv() + if errors.Is(err, io.EOF) { + break + } + if err != nil { + return nil, fmt.Errorf("cannot receive resource link: %w", err) + } + links = append(links, link) + } + return links, nil +} + +func (requestHandler *RequestHandler) getThings(w http.ResponseWriter, r *http.Request) { + resLinks, err := requestHandler.getResourceLinks(r.Context(), nil, []string{bridgeResourcesTD.ResourceType}) + if err != nil { + serverMux.WriteError(w, err) + return + } + hubCfg, err := requestHandler.client.GrpcGatewayClient().GetHubConfiguration(r.Context(), &pb.HubConfigurationRequest{}) + if err != nil { + serverMux.WriteError(w, err) + return + } + + links := make([]ThingLink, 0, len(resLinks)) + for _, l := range resLinks { + links = append(links, ThingLink{ + Href: "/" + l.GetDeviceId(), + Rel: ThingLinkRelationItem, + }) + } + var td wotTD.ThingDescription + ThingSetSecurity(&td, requestHandler.openIDConfig) + + things := GetThingsResponse{ + Base: requestHandler.config.UI.WebConfiguration.HTTPGatewayAddress + uri.Things, + Links: links, + Security: td.Security, + SecurityDefinitions: td.SecurityDefinitions, + ID: "urn:uuid:" + hubCfg.GetId(), + } + if err := jsonResponseWriter(w, things); err != nil { + log.Errorf("failed to write response: %v", err) + } +} + +func CreateHTTPForms(hrefUri *url.URL, opsBits resources.SupportedOperation, contentType message.MediaType) []wotTD.FormElementProperty { + supportedByOps := map[resources.SupportedOperation]wotTD.StickyDescription{ + resources.SupportedOperationRead: wotTD.Readproperty, + resources.SupportedOperationWrite: wotTD.Writeproperty, + } + + ops := make([]string, 0, len(supportedByOps)) + for opBit, op := range supportedByOps { + if opsBits.HasOperation(opBit) { + ops = append(ops, string(op)) + } + } + if len(ops) == 0 { + return nil + } + q := hrefUri.Query() + if len(q) > 0 && q.Has("di") { + q.Del("di") + } + q.Add(uri.OnlyContentQueryKey, "1") + hrefUri.RawQuery = q.Encode() + return []wotTD.FormElementProperty{ + { + ContentType: bridgeDeviceTD.StringToPtr(contentType.String()), + Href: *hrefUri, + Op: &wotTD.FormElementPropertyOp{ + StringArray: ops, + }, + }, + } +} + +func patchProperty(pe wotTD.PropertyElement, deviceID, href string, contentType message.MediaType) (wotTD.PropertyElement, error) { + deviceUUID, err := uuid.Parse(deviceID) + if err != nil { + return wotTD.PropertyElement{}, fmt.Errorf("cannot parse deviceID: %w", err) + } + propertyBaseURL := "/" + uri.DevicesPathKey + "/" + deviceID + "/" + uri.ResourcesPathKey + patchFnMap := map[string]func(wotTD.PropertyElement) (wotTD.PropertyElement, error){ + schemaDevice.ResourceURI: func(pe wotTD.PropertyElement) (wotTD.PropertyElement, error) { + return bridgeResourcesTD.PatchDeviceResourcePropertyElement(pe, deviceUUID, propertyBaseURL, contentType, "", CreateHTTPForms) + }, + schemaMaintenance.ResourceURI: func(pe wotTD.PropertyElement) (wotTD.PropertyElement, error) { + return bridgeResourcesTD.PatchMaintenanceResourcePropertyElement(pe, deviceUUID, propertyBaseURL, contentType, CreateHTTPForms) + }, + schemaCloud.ResourceURI: func(pe wotTD.PropertyElement) (wotTD.PropertyElement, error) { + return bridgeResourcesTD.PatchCloudResourcePropertyElement(pe, deviceUUID, propertyBaseURL, contentType, CreateHTTPForms) + }, + schemaCredential.ResourceURI: func(pe wotTD.PropertyElement) (wotTD.PropertyElement, error) { + return bridgeResourcesTD.PatchCredentialResourcePropertyElement(pe, deviceUUID, propertyBaseURL, contentType, CreateHTTPForms) + }, + } + patchFn, ok := patchFnMap[href] + if ok { + pe, err = patchFn(pe) + if err != nil { + return wotTD.PropertyElement{}, err + } + return pe, nil + } + + propOps := bridgeDeviceTD.GetPropertyElementOperations(pe) + pe, err = bridgeDeviceTD.PatchPropertyElement(pe, nil, deviceUUID, propertyBaseURL+href, + propOps.ToSupportedOperations(), contentType, CreateHTTPForms) + if err != nil { + return wotTD.PropertyElement{}, err + } + return pe, nil +} + +var validRefs = map[string]struct{}{ + ThingLinkRelationItem: {}, + ThingLinkRelationCollection: {}, +} + +func isDeviceLink(le wotTD.IconLinkElement) (string, bool) { + if le.Href == "" { + return "", false + } + if le.Href[0] != '/' { + return "", false + } + if le.Rel == nil { + return "", false + } + + if _, ok := validRefs[*le.Rel]; !ok { + return "", false + } + linkedDeviceID := le.Href + if linkedDeviceID[0] == '/' { + linkedDeviceID = linkedDeviceID[1:] + } + uuidDeviceID, err := uuid.Parse(linkedDeviceID) + if err != nil { + return "", false + } + if uuidDeviceID == uuid.Nil { + return "", false + } + return linkedDeviceID, true +} + +func getLinkedDevices(links []wotTD.IconLinkElement) []string { + devices := make([]string, 0, len(links)) + for _, l := range links { + if deviceID, ok := isDeviceLink(l); ok { + devices = append(devices, deviceID) + } + } + return devices +} + +func ThingPatchLink(le wotTD.IconLinkElement, validateDevice map[string]struct{}) (wotTD.IconLinkElement, bool) { + if le.Href == "" { + return wotTD.IconLinkElement{}, false + } + device, ok := isDeviceLink(le) + if !ok { + return le, true + } + if len(validateDevice) == 0 { + return wotTD.IconLinkElement{}, false + } + if _, ok := validateDevice[device]; !ok { + return wotTD.IconLinkElement{}, false + } + le.Href = "/" + uri.ThingsPathKey + le.Href + return le, true +} + +func makeDevicePropertiesValidator(deviceID string, links []*events.ResourceLinksPublished) (map[string]struct{}, bool) { + for _, l := range links { + if l.GetDeviceId() == deviceID { + validateProperties := map[string]struct{}{} + for _, r := range l.GetResources() { + validateProperties[r.GetHref()] = struct{}{} + } + return validateProperties, true + } + } + return nil, false +} + +func makeDeviceLinkValidator(links []*events.ResourceLinksPublished) map[string]struct{} { + validator := make(map[string]struct{}) + for _, l := range links { + validator[l.GetDeviceId()] = struct{}{} + } + return validator +} + +func (requestHandler *RequestHandler) thingSetBase(td *wotTD.ThingDescription) error { + baseURL := requestHandler.config.UI.WebConfiguration.HTTPGatewayAddress + uri.API + base, err := url.Parse(baseURL) + if err != nil { + return fmt.Errorf("cannot parse base url: %w", err) + } + td.Base = *base + return nil +} + +func (requestHandler *RequestHandler) thingSetProperties(ctx context.Context, deviceID string, td *wotTD.ThingDescription) error { + deviceLinks, err := requestHandler.getResourceLinks(ctx, []string{deviceID}, nil) + if err != nil { + return fmt.Errorf("cannot get resource links: %w", err) + } + validateProperties, ok := makeDevicePropertiesValidator(deviceID, deviceLinks) + if !ok { + return fmt.Errorf("cannot get resource links for device %v", deviceID) + } + for href, prop := range td.Properties { + _, ok := validateProperties[href] + if !ok { + _, ok = validateProperties["/"+href] + } + if !ok { + delete(td.Properties, href) + continue + } + patchedProp, err := patchProperty(prop, deviceID, href, message.AppJSON) + if err != nil { + return fmt.Errorf("cannot patch device resource property element: %w", err) + } + td.Properties[href] = patchedProp + } + return nil +} + +func (requestHandler *RequestHandler) thingSetLinks(ctx context.Context, td *wotTD.ThingDescription) { + linkedDevices := getLinkedDevices(td.Links) + var validLinkedDevices map[string]struct{} + if len(linkedDevices) > 0 { + links, err := requestHandler.getResourceLinks(ctx, linkedDevices, []string{bridgeResourcesTD.ResourceType}) + if err == nil { + validLinkedDevices = makeDeviceLinkValidator(links) + } + } + patchedLinks := make([]wotTD.IconLinkElement, 0, len(td.Links)) + for _, link := range td.Links { + patchedLink, ok := ThingPatchLink(link, validLinkedDevices) + if !ok { + continue + } + patchedLinks = append(patchedLinks, patchedLink) + } + if len(patchedLinks) == 0 { + td.Links = nil + } else { + td.Links = patchedLinks + } +} + +func ThingSetSecurity(td *wotTD.ThingDescription, openIDConfig openid.Config) { + td.Security = &wotTD.TypeDeclaration{ + String: bridgeDeviceTD.StringToPtr("oauth2_sc"), + } + td.SecurityDefinitions = map[string]wotTD.SecurityScheme{ + "oauth2_sc": { + Scheme: "oauth2", + Flow: bridgeDeviceTD.StringToPtr("code"), + Authorization: &openIDConfig.AuthURL, + Token: &openIDConfig.TokenURL, + }, + } +} + +func (requestHandler *RequestHandler) thingDescriptionResponse(ctx context.Context, w http.ResponseWriter, rec *httptest.ResponseRecorder, writeError func(w http.ResponseWriter, err error), deviceID string) { + content := jsoniter.Get(rec.Body.Bytes(), streamResponseKey, "data", "content") + if content.ValueType() != jsoniter.ObjectValue { + writeError(w, errors.New("cannot decode thingDescription content")) + return + } + var td wotTD.ThingDescription + err := td.UnmarshalJSON([]byte(content.ToString())) + if err != nil { + writeError(w, fmt.Errorf("cannot decode thingDescription content: %w", err)) + return + } + + // .security + ThingSetSecurity(&td, requestHandler.openIDConfig) + + // .base + if err = requestHandler.thingSetBase(&td); err != nil { + writeError(w, fmt.Errorf("cannot set base url: %w", err)) + return + } + + // .properties.forms + if err = requestHandler.thingSetProperties(ctx, deviceID, &td); err != nil { + writeError(w, fmt.Errorf("cannot set properties: %w", err)) + } + + // .links + requestHandler.thingSetLinks(ctx, &td) + + // marshal thingDescription + data, err := td.MarshalJSON() + if err != nil { + writeError(w, fmt.Errorf("cannot encode thingDescription: %w", err)) + return + } + // copy everything from response recorder + // to actual response writer + for k, v := range rec.Header() { + w.Header()[k] = v + } + w.WriteHeader(rec.Code) + _, err = w.Write(data) + if err != nil { + writeError(w, kitNetGrpc.ForwardErrorf(codes.Internal, "cannot encode response: %v", err)) + } +} + +func (requestHandler *RequestHandler) getThing(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + deviceID := vars[uri.DeviceIDKey] + rec, _, err := requestHandler.serveResourceRequest(r, deviceID, bridgeResourcesTD.ResourceURI, "", "") + if err != nil { + serverMux.WriteError(w, err) + return + } + requestHandler.thingDescriptionResponse(r.Context(), w, rec, serverMux.WriteError, deviceID) +} diff --git a/http-gateway/service/getThings_test.go b/http-gateway/service/getThings_test.go new file mode 100644 index 000000000..176c9142d --- /dev/null +++ b/http-gateway/service/getThings_test.go @@ -0,0 +1,452 @@ +package service_test + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "strconv" + "testing" + + "github.com/google/uuid" + bridgeTD "github.com/plgd-dev/device/v2/bridge/device/thingDescription" + bridgeResourcesTD "github.com/plgd-dev/device/v2/bridge/resources/thingDescription" + "github.com/plgd-dev/device/v2/client/core" + bridgeDevice "github.com/plgd-dev/device/v2/cmd/bridge-device/device" + "github.com/plgd-dev/device/v2/pkg/codec/json" + deviceCoap "github.com/plgd-dev/device/v2/pkg/net/coap" + schemaDevice "github.com/plgd-dev/device/v2/schema/device" + schemaMaintenance "github.com/plgd-dev/device/v2/schema/maintenance" + "github.com/plgd-dev/go-coap/v3/message" + "github.com/plgd-dev/hub/v2/grpc-gateway/pb" + httpgwService "github.com/plgd-dev/hub/v2/http-gateway/service" + httpgwTest "github.com/plgd-dev/hub/v2/http-gateway/test" + httpgwUri "github.com/plgd-dev/hub/v2/http-gateway/uri" + isPb "github.com/plgd-dev/hub/v2/identity-store/pb" + isTest "github.com/plgd-dev/hub/v2/identity-store/test" + kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc" + "github.com/plgd-dev/hub/v2/pkg/security/openid" + "github.com/plgd-dev/hub/v2/resource-aggregate/commands" + raPb "github.com/plgd-dev/hub/v2/resource-aggregate/service" + raTest "github.com/plgd-dev/hub/v2/resource-aggregate/test" + "github.com/plgd-dev/hub/v2/test" + "github.com/plgd-dev/hub/v2/test/config" + "github.com/plgd-dev/hub/v2/test/device/bridge" + oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" + "github.com/plgd-dev/hub/v2/test/service" + vd "github.com/plgd-dev/hub/v2/test/virtual-device" + "github.com/stretchr/testify/require" + wotTD "github.com/web-of-things-open-source/thingdescription-go/thingDescription" + "golang.org/x/sync/semaphore" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" +) + +type virtualDevice struct { + name string + deviceID string + tdEnabled bool +} + +func createDevices(ctx context.Context, t *testing.T, numDevices int, protocol commands.Connection_Protocol) []virtualDevice { + ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) + + isConn, err := grpc.NewClient(config.IDENTITY_STORE_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + RootCAs: test.GetRootCertificatePool(t), + }))) + require.NoError(t, err) + defer func() { + _ = isConn.Close() + }() + isClient := isPb.NewIdentityStoreClient(isConn) + + raConn, err := grpc.NewClient(config.RESOURCE_AGGREGATE_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + RootCAs: test.GetRootCertificatePool(t), + }))) + require.NoError(t, err) + defer func() { + _ = raConn.Close() + }() + raClient := raPb.NewResourceAggregateClient(raConn) + + devices := make([]virtualDevice, 0, numDevices) + for i := 0; i < numDevices; i++ { + tdEnabled := (i%2 == 0) + devices = append(devices, virtualDevice{ + name: fmt.Sprintf("dev-%v", i), + deviceID: uuid.NewString(), + tdEnabled: tdEnabled, + }) + } + + numGoRoutines := int64(8) + sem := semaphore.NewWeighted(numGoRoutines) + for i := range devices { + err = sem.Acquire(ctx, 1) + require.NoError(t, err) + go func(dev virtualDevice) { + vd.CreateDevice(ctx, t, dev.name, dev.deviceID, 0, dev.tdEnabled, protocol, isClient, raClient) + sem.Release(1) + }(devices[i]) + } + err = sem.Acquire(ctx, numGoRoutines) + require.NoError(t, err) + return devices +} + +func TestRequestHandlerGetThings(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), config.TEST_TIMEOUT) + defer cancel() + + const services = service.SetUpServicesOAuth | service.SetUpServicesId | service.SetUpServicesResourceDirectory | + service.SetUpServicesGrpcGateway | service.SetUpServicesResourceAggregate + isConfig := isTest.MakeConfig(t) + isConfig.APIs.GRPC.TLS.ClientCertificateRequired = false + raConfig := raTest.MakeConfig(t) + raConfig.APIs.GRPC.TLS.ClientCertificateRequired = false + tearDown := service.SetUpServices(ctx, t, services, service.WithISConfig(isConfig), service.WithRAConfig(raConfig)) + defer tearDown() + + httpgwCfg := httpgwTest.MakeConfig(t, true) + shutdownHttp := httpgwTest.New(t, httpgwCfg) + defer shutdownHttp() + + token := oauthTest.GetDefaultAccessToken(t) + ctx = kitNetGrpc.CtxWithToken(ctx, token) + + numDevices := 10 + vds := createDevices(ctx, t, numDevices, test.StringToApplicationProtocol(config.ACTIVE_COAP_SCHEME)) + + rb := httpgwTest.NewRequest(http.MethodGet, httpgwUri.Things, nil).AuthToken(token) + resp := httpgwTest.HTTPDo(t, rb.Build()) + defer func() { + _ = resp.Body.Close() + }() + + var v httpgwService.GetThingsResponse + err := httpgwTest.UnmarshalJson(resp.StatusCode, resp.Body, &v) + require.NoError(t, err) + require.Equal(t, httpgwCfg.UI.WebConfiguration.HTTPGatewayAddress+httpgwUri.Things, v.Base) + vdsWithTD := []virtualDevice{} + for _, vd := range vds { + if vd.tdEnabled { + vdsWithTD = append(vdsWithTD, vd) + } + } + require.Len(t, v.Links, len(vdsWithTD)) + for _, dev := range vdsWithTD { + require.Contains(t, v.Links, httpgwService.ThingLink{ + Href: "/" + dev.deviceID, + Rel: httpgwService.ThingLinkRelationItem, + }) + } +} + +func TestBridgeDeviceGetThings(t *testing.T) { + bridgeDeviceCfg, err := test.GetBridgeDeviceConfig() + require.NoError(t, err) + ctx, cancel := context.WithTimeout(context.Background(), config.TEST_TIMEOUT) + defer cancel() + tearDown := service.SetUp(ctx, t) + defer tearDown() + token := oauthTest.GetDefaultAccessToken(t) + ctx = kitNetGrpc.CtxWithToken(ctx, token) + + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + RootCAs: test.GetRootCertificatePool(t), + }))) + require.NoError(t, err) + defer func() { + _ = conn.Close() + }() + c := pb.NewGrpcGatewayClient(conn) + + httpgwCfg := httpgwTest.MakeConfig(t, true) + shutdownHttp := httpgwTest.New(t, httpgwCfg) + defer shutdownHttp() + + var devIDs []string + for i := 0; i < bridgeDeviceCfg.NumGeneratedBridgedDevices; i++ { + bdName := test.TestBridgeDeviceInstanceName(strconv.Itoa(i)) + bdID := test.MustFindDeviceByName(bdName, func(d *core.Device) deviceCoap.OptionFunc { + return deviceCoap.WithQuery("di=" + d.DeviceID()) + }) + devIDs = append(devIDs, bdID) + bd := bridge.NewDevice(bdID, bdName, bridgeDeviceCfg.NumResourcesPerDevice, true) + shutdownBd := test.OnboardDevice(ctx, t, c, bd, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, bd.GetDefaultResources()) + defer shutdownBd() + } + + rb := httpgwTest.NewRequest(http.MethodGet, httpgwUri.Things, nil).AuthToken(token) + resp := httpgwTest.HTTPDo(t, rb.Build()) + defer func() { + _ = resp.Body.Close() + }() + + var v httpgwService.GetThingsResponse + err = httpgwTest.UnmarshalJson(resp.StatusCode, resp.Body, &v) + require.NoError(t, err) + require.Equal(t, httpgwCfg.UI.WebConfiguration.HTTPGatewayAddress+httpgwUri.Things, v.Base) + require.Len(t, v.Links, bridgeDeviceCfg.NumGeneratedBridgedDevices) + for _, devID := range devIDs { + require.Contains(t, v.Links, httpgwService.ThingLink{ + Href: "/" + devID, + Rel: httpgwService.ThingLinkRelationItem, + }) + } +} + +func getPatchedTD(t *testing.T, deviceCfg bridgeDevice.Config, deviceID string, links []wotTD.IconLinkElement, validateDevices map[string]struct{}, title, host string) *wotTD.ThingDescription { + td, err := bridgeDevice.GetThingDescription(deviceCfg.ThingDescription.File, deviceCfg.NumResourcesPerDevice) + require.NoError(t, err) + + baseURL := host + httpgwUri.API + base, err := url.Parse(baseURL) + require.NoError(t, err) + td.Base = *base + td.Title = title + id, err := bridgeTD.GetThingDescriptionID(deviceID) + require.NoError(t, err) + td.ID = id + + deviceUUID, err := uuid.Parse(deviceID) + require.NoError(t, err) + propertyBaseURL := "/" + httpgwUri.DevicesPathKey + "/" + deviceID + "/" + httpgwUri.ResourcesPathKey + dev, ok := bridgeResourcesTD.GetOCFResourcePropertyElement(schemaDevice.ResourceURI) + require.True(t, ok) + dev, err = bridgeResourcesTD.PatchDeviceResourcePropertyElement(dev, deviceUUID, propertyBaseURL, message.AppJSON, bridgeDevice.DeviceResourceType, httpgwService.CreateHTTPForms) + require.NoError(t, err) + schemaMap := bridgeDevice.GetDataSchemaForAdditionalProperties() + for name, schema := range schemaMap { + dev.Properties.DataSchemaMap[name] = schema + } + td.Properties[schemaDevice.ResourceURI] = dev + + httpgwService.ThingSetSecurity(&td, openid.Config{ + TokenURL: "https://localhost:20009/oauth/token", + AuthURL: "https://localhost:20009/authorize", + }) + + mnt, ok := bridgeResourcesTD.GetOCFResourcePropertyElement(schemaMaintenance.ResourceURI) + require.True(t, ok) + mnt, err = bridgeResourcesTD.PatchMaintenanceResourcePropertyElement(mnt, deviceUUID, propertyBaseURL, message.AppJSON, httpgwService.CreateHTTPForms) + require.NoError(t, err) + td.Properties[schemaMaintenance.ResourceURI] = mnt + + for i := 0; i < deviceCfg.NumResourcesPerDevice; i++ { + href := bridgeDevice.GetTestResourceHref(i) + prop := bridgeDevice.GetPropertyDescriptionForTestResource() + prop, err := bridgeDevice.PatchTestResourcePropertyElement(prop, deviceUUID, propertyBaseURL+href, message.AppJSON, httpgwService.CreateHTTPForms) + require.NoError(t, err) + td.Properties[href] = prop + } + + expectedLinks := make([]wotTD.IconLinkElement, 0, len(links)) + for _, link := range links { + patchedLink, ok := httpgwService.ThingPatchLink(link, validateDevices) + if !ok { + continue + } + expectedLinks = append(expectedLinks, patchedLink) + } + td.Links = expectedLinks + + return &td +} + +func bridgeDeviceInstanceName(idx int) string { + return test.TestBridgeDeviceInstanceName(strconv.Itoa(idx)) +} + +func onboardBridgeDevice(ctx context.Context, t *testing.T, idx int, c pb.GrpcGatewayClient, bridgeDeviceCfg bridgeDevice.Config) (string, func()) { + bdName := bridgeDeviceInstanceName(idx) + bdID := test.MustFindDeviceByName(bdName, func(d *core.Device) deviceCoap.OptionFunc { + return deviceCoap.WithQuery("di=" + d.DeviceID()) + }) + bd := bridge.NewDevice(bdID, bdName, bridgeDeviceCfg.NumResourcesPerDevice, true) + shutdownBd := test.OnboardDevice(ctx, t, c, bd, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, bd.GetDefaultResources()) + return bdID, shutdownBd +} + +func TestBridgeDeviceGetThing(t *testing.T) { + bridgeDeviceCfg, err := test.GetBridgeDeviceConfig() + require.NoError(t, err) + + ctx, cancel := context.WithTimeout(context.Background(), config.TEST_TIMEOUT) + defer cancel() + raCfg := raTest.MakeConfig(t) + raCfg.APIs.GRPC.TLS.ClientCertificateRequired = false + tearDown := service.SetUp(ctx, t, service.WithRAConfig(raCfg)) + defer tearDown() + token := oauthTest.GetDefaultAccessToken(t) + ctx = kitNetGrpc.CtxWithToken(ctx, token) + + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + RootCAs: test.GetRootCertificatePool(t), + }))) + require.NoError(t, err) + defer func() { + _ = conn.Close() + }() + c := pb.NewGrpcGatewayClient(conn) + + httpgwCfg := httpgwTest.MakeConfig(t, true) + shutdownHttp := httpgwTest.New(t, httpgwCfg) + defer shutdownHttp() + + deviceIDs := make([]string, 0, 2) + validLinkedDevices := make(map[string]struct{}, 2) + for i := 0; i < 2; i++ { + bdID, shutdownBd := onboardBridgeDevice(ctx, t, i, c, bridgeDeviceCfg) + defer shutdownBd() + deviceIDs = append(deviceIDs, bdID) + validLinkedDevices[bdID] = struct{}{} + } + + // update TD links in resource twin + wotRes, err := c.GetResources(ctx, &pb.GetResourcesRequest{ + ResourceIdFilter: []*pb.ResourceIdFilter{ + { + ResourceId: &commands.ResourceId{ + DeviceId: deviceIDs[0], + Href: bridgeResourcesTD.ResourceURI, + }, + }, + }, + }) + require.NoError(t, err) + resources := make([]*pb.Resource, 0, 1) + for { + res, errR := wotRes.Recv() + if errors.Is(errR, io.EOF) { + break + } + require.NoError(t, errR) + resources = append(resources, res) + } + require.Len(t, resources, 1) + + var updateLinksTD wotTD.ThingDescription + err = json.Decode(resources[0].GetData().GetContent().GetData(), &updateLinksTD) + require.NoError(t, err) + links := []wotTD.IconLinkElement{ + { + Rel: bridgeTD.StringToPtr("icon"), + Href: "https://example.com/icon.png", + }, + { + Rel: bridgeTD.StringToPtr(httpgwService.ThingLinkRelationItem), + Href: "/" + deviceIDs[1], + }, + { + Rel: bridgeTD.StringToPtr(httpgwService.ThingLinkRelationCollection), + Href: "/" + deviceIDs[1], + }, + { + Rel: bridgeTD.StringToPtr(httpgwService.ThingLinkRelationItem), + Href: "/" + uuid.NewString(), + }, + } + updateLinksTD.Links = links + data, err := json.Encode(updateLinksTD) + require.NoError(t, err) + + sub, err := c.SubscribeToEvents(ctx) + require.NoError(t, err) + + err = sub.Send(&pb.SubscribeToEvents{ + Action: &pb.SubscribeToEvents_CreateSubscription_{CreateSubscription: &pb.SubscribeToEvents_CreateSubscription{ + EventFilter: []pb.SubscribeToEvents_CreateSubscription_Event{pb.SubscribeToEvents_CreateSubscription_RESOURCE_CHANGED}, + ResourceIdFilter: []*pb.ResourceIdFilter{ + { + ResourceId: resources[0].GetData().GetResourceId(), + }, + }, + }}, + }) + require.NoError(t, err) + s, err := sub.Recv() + require.NoError(t, err) + require.Equal(t, pb.Event_OperationProcessed_ErrorStatus_OK, s.GetOperationProcessed().GetErrorStatus().GetCode()) + + // overwrite TD links in resource twin + raConn, err := grpc.NewClient(config.RESOURCE_AGGREGATE_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + RootCAs: test.GetRootCertificatePool(t), + }))) + require.NoError(t, err) + defer func() { + _ = raConn.Close() + }() + raC := raPb.NewResourceAggregateClient(raConn) + _, err = raC.NotifyResourceChanged(ctx, &commands.NotifyResourceChangedRequest{ + ResourceId: resources[0].GetData().GetResourceId(), + Status: commands.Status_OK, + Content: &commands.Content{ + Data: data, + CoapContentFormat: int32(message.AppJSON), + ContentType: message.AppJSON.String(), + }, + CommandMetadata: &commands.CommandMetadata{ + ConnectionId: "test", + Sequence: 1, + }, + }) + require.NoError(t, err) + + ev, err := sub.Recv() + require.NoError(t, err) + require.Equal(t, commands.Status_OK, ev.GetResourceChanged().GetStatus()) + + err = sub.CloseSend() + require.NoError(t, err) + + type args struct { + accept string + deviceID string + } + tests := []struct { + name string + args args + want *wotTD.ThingDescription + wantCode int + }{ + { + name: "json: get from resource twin", + args: args{ + deviceID: deviceIDs[0], + }, + want: getPatchedTD(t, bridgeDeviceCfg, deviceIDs[0], links, validLinkedDevices, bridgeDeviceInstanceName(0), httpgwCfg.UI.WebConfiguration.HTTPGatewayAddress), + wantCode: http.StatusOK, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rb := httpgwTest.NewRequest(http.MethodGet, httpgwUri.AliasDeviceThing, nil).AuthToken(token).Accept(tt.args.accept).DeviceId(tt.args.deviceID) + resp := httpgwTest.HTTPDo(t, rb.Build()) + defer func() { + _ = resp.Body.Close() + }() + require.Equal(t, tt.wantCode, resp.StatusCode) + values := make([]*wotTD.ThingDescription, 0, 1) + for { + var td wotTD.ThingDescription + err := json.ReadFrom(resp.Body, &td) + if errors.Is(err, io.EOF) { + break + } + require.NoError(t, err) + values = append(values, &td) + } + if tt.wantCode != http.StatusOK { + require.Empty(t, values) + return + } + require.Len(t, values, 1) + test.CmpThingDescription(t, tt.want, values[0]) + }) + } +} diff --git a/http-gateway/service/getWebConfiguration_test.go b/http-gateway/service/getWebConfiguration_test.go index c65d35e9f..6f3f5d1f0 100644 --- a/http-gateway/service/getWebConfiguration_test.go +++ b/http-gateway/service/getWebConfiguration_test.go @@ -2,7 +2,6 @@ package service_test import ( "context" - "encoding/json" "io" "net/http" "os" @@ -18,19 +17,6 @@ import ( "github.com/stretchr/testify/require" ) -func unmarshalWebConfiguration(code int, input io.Reader, v *httpgwService.WebConfiguration) error { - var data json.RawMessage - err := json.NewDecoder(input).Decode(&data) - if err != nil { - return err - } - if code != http.StatusOK { - return httpgwTest.UnmarshalError(data) - } - err = json.Unmarshal(data, v) - return err -} - func TestRegexpAPI(t *testing.T) { tests := []struct { val string @@ -104,7 +90,7 @@ func TestRequestHandlerGetWebConfiguration(t *testing.T) { assert.Equal(t, tt.wantHTTPCode, resp.StatusCode) var got httpgwService.WebConfiguration - err := unmarshalWebConfiguration(resp.StatusCode, resp.Body, &got) + err := httpgwTest.UnmarshalJson(resp.StatusCode, resp.Body, &got) if tt.wantErr { require.Error(t, err) return @@ -159,7 +145,7 @@ func TestRequestHandlerGetWebDirectory(t *testing.T) { want, err := os.ReadFile(tt.wantFile) require.NoError(t, err) - require.Equal(t, got, want) + require.Equal(t, want, got) }) } } diff --git a/http-gateway/service/requestHandler.go b/http-gateway/service/requestHandler.go index e74cc7364..66c15d7c5 100644 --- a/http-gateway/service/requestHandler.go +++ b/http-gateway/service/requestHandler.go @@ -16,13 +16,17 @@ import ( "github.com/plgd-dev/hub/v2/http-gateway/uri" "github.com/plgd-dev/hub/v2/pkg/log" kitHttp "github.com/plgd-dev/hub/v2/pkg/net/http" + "github.com/plgd-dev/hub/v2/pkg/security/openid" + pkgStrings "github.com/plgd-dev/hub/v2/pkg/strings" ) // RequestHandler for handling incoming request type RequestHandler struct { - client *client.Client - config *Config - mux *runtime.ServeMux + client *client.Client + config *Config + mux *runtime.ServeMux + openIDConfig openid.Config + logger log.Logger } func matchPrefixAndSplitURIPath(requestURI, prefix string) []string { @@ -38,22 +42,30 @@ func matchPrefixAndSplitURIPath(requestURI, prefix string) []string { return strings.Split(p, "/") } +func unescapeString(s string) string { + newS, err := pkgStrings.Unescape(s, pkgStrings.UnescapingModeAllCharacters, false) + if err != nil { + return s + } + return newS +} + func resourcePendingCommandsMatcher(r *http.Request, rm *mux.RouteMatch) bool { paths := matchPrefixAndSplitURIPath(r.RequestURI, uri.Devices) if len(paths) > 3 && paths[1] == uri.ResourcesPathKey && strings.Contains(paths[len(paths)-1], uri.PendingCommandsPathKey) { if rm.Vars == nil { rm.Vars = make(map[string]string) } - rm.Vars[uri.DeviceIDKey] = paths[0] - rm.Vars[uri.ResourceHrefKey] = strings.Split("/"+strings.Join(paths[2:len(paths)-1], "/"), "?")[0] + rm.Vars[uri.DeviceIDKey] = unescapeString(paths[0]) + rm.Vars[uri.ResourceHrefKey] = unescapeString(strings.Split("/"+strings.Join(paths[2:len(paths)-1], "/"), "?")[0]) return true } if len(paths) > 4 && paths[1] == uri.ResourcesPathKey && strings.Contains(paths[len(paths)-2], uri.PendingCommandsPathKey) { if rm.Vars == nil { rm.Vars = make(map[string]string) } - rm.Vars[uri.DeviceIDKey] = paths[0] - rm.Vars[uri.ResourceHrefKey] = "/" + strings.Join(paths[2:len(paths)-2], "/") + rm.Vars[uri.DeviceIDKey] = unescapeString(paths[0]) + rm.Vars[uri.ResourceHrefKey] = unescapeString("/" + strings.Join(paths[2:len(paths)-2], "/")) rm.Vars[uri.CorrelationIDKey] = strings.Split(paths[len(paths)-1], "?")[0] return true } @@ -68,8 +80,8 @@ func resourceMatcher(r *http.Request, rm *mux.RouteMatch) bool { if rm.Vars == nil { rm.Vars = make(map[string]string) } - rm.Vars[uri.DeviceIDKey] = paths[0] - rm.Vars[uri.ResourceHrefKey] = strings.Split("/"+strings.Join(paths[2:], "/"), "?")[0] + rm.Vars[uri.DeviceIDKey] = unescapeString(paths[0]) + rm.Vars[uri.ResourceHrefKey] = unescapeString(strings.Split("/"+strings.Join(paths[2:], "/"), "?")[0]) return true } return false @@ -81,8 +93,8 @@ func resourceLinksMatcher(r *http.Request, rm *mux.RouteMatch) bool { if rm.Vars == nil { rm.Vars = make(map[string]string) } - rm.Vars[uri.DeviceIDKey] = paths[0] - rm.Vars[uri.ResourceHrefKey] = strings.Split("/"+strings.Join(paths[2:], "/"), "?")[0] + rm.Vars[uri.DeviceIDKey] = unescapeString(paths[0]) + rm.Vars[uri.ResourceHrefKey] = unescapeString(strings.Split("/"+strings.Join(paths[2:], "/"), "?")[0]) return true } return false @@ -98,8 +110,21 @@ func resourceEventsMatcher(r *http.Request, rm *mux.RouteMatch) bool { if rm.Vars == nil { rm.Vars = make(map[string]string) } - rm.Vars[uri.DeviceIDKey] = paths[0] - rm.Vars[uri.ResourceHrefKey] = "/" + strings.Join(paths[2:len(paths)-1], "/") + rm.Vars[uri.DeviceIDKey] = unescapeString(paths[0]) + rm.Vars[uri.ResourceHrefKey] = unescapeString("/" + strings.Join(paths[2:len(paths)-1], "/")) + return true + } + return false +} + +func thingMatcher(r *http.Request, rm *mux.RouteMatch) bool { + // /api/v1/things/{deviceId} + paths := matchPrefixAndSplitURIPath(r.RequestURI, uri.Things) + if len(paths) == 1 { + if rm.Vars == nil { + rm.Vars = make(map[string]string) + } + rm.Vars[uri.DeviceIDKey] = unescapeString(paths[0]) return true } return false @@ -144,10 +169,12 @@ func (requestHandler *RequestHandler) setupUIHandler(r *mux.Router) { } // NewHTTP returns HTTP handler -func NewRequestHandler(config *Config, r *mux.Router, client *client.Client) (*RequestHandler, error) { +func NewRequestHandler(config *Config, r *mux.Router, client *client.Client, openIDConfig openid.Config, logger log.Logger) (*RequestHandler, error) { requestHandler := &RequestHandler{ - client: client, - config: config, + client: client, + config: config, + openIDConfig: openIDConfig, + logger: logger, mux: serverMux.New( runtime.WithMarshalerOption(ApplicationSubscribeToEventsMIMEWildcard, newSubscribeToEventsMarshaler(serverMux.NewJsonMarshaler())), runtime.WithMarshalerOption(ApplicationSubscribeToEventsProtoJsonContentType, serverMux.NewJsonpbMarshaler()), @@ -164,6 +191,7 @@ func NewRequestHandler(config *Config, r *mux.Router, client *client.Client) (*R r.HandleFunc(uri.AliasDeviceEvents, requestHandler.getEvents).Methods(http.MethodGet) r.HandleFunc(uri.Configuration, requestHandler.getHubConfiguration).Methods(http.MethodGet) r.HandleFunc(uri.HubConfiguration, requestHandler.getHubConfiguration).Methods(http.MethodGet) + r.HandleFunc(uri.Things, requestHandler.getThings).Methods(http.MethodGet) r.PathPrefix(uri.Devices).Methods(http.MethodPost).MatcherFunc(resourceLinksMatcher).HandlerFunc(requestHandler.createResource) r.PathPrefix(uri.Devices).Methods(http.MethodGet).MatcherFunc(resourcePendingCommandsMatcher).HandlerFunc(requestHandler.getResourcePendingCommands) @@ -172,6 +200,8 @@ func NewRequestHandler(config *Config, r *mux.Router, client *client.Client) (*R r.PathPrefix(uri.Devices).Methods(http.MethodPut).MatcherFunc(resourceMatcher).HandlerFunc(requestHandler.updateResource) r.PathPrefix(uri.Devices).Methods(http.MethodGet).MatcherFunc(resourceEventsMatcher).HandlerFunc(requestHandler.getEvents) + r.PathPrefix(uri.Things).Methods(http.MethodGet).MatcherFunc(thingMatcher).HandlerFunc(requestHandler.getThing) + // register grpc-proxy handler if err := pb.RegisterGrpcGatewayHandlerClient(context.Background(), requestHandler.mux, requestHandler.client.GrpcGatewayClient()); err != nil { return nil, fmt.Errorf("failed to register grpc-gateway handler: %w", err) diff --git a/http-gateway/service/service.go b/http-gateway/service/service.go index 47d9344b8..8f4161b2b 100644 --- a/http-gateway/service/service.go +++ b/http-gateway/service/service.go @@ -79,14 +79,14 @@ func New(ctx context.Context, config Config, fileWatcher *fsnotify.Watcher, logg return nil, fmt.Errorf("cannot connect to grpc-gateway: %w", err) } s.AddCloseFunc(func() { - err := grpcConn.Close() - if err != nil { - logger.Errorf("error occurs during close connection to grpc-gateway: %v", err) + errC := grpcConn.Close() + if errC != nil { + logger.Errorf("error occurs during close connection to grpc-gateway: %v", errC) } }) grpcClient := pb.NewGrpcGatewayClient(grpcConn.GRPC()) client := client.New(grpcClient) - _, err = NewRequestHandler(&config, s.GetRouter(), client) + _, err = NewRequestHandler(&config, s.GetRouter(), client, validator.OpenIDConfiguration(), logger) if err != nil { var errors *multierror.Error errors = multierror.Append(errors, fmt.Errorf("cannot create request handler: %w", err)) diff --git a/http-gateway/service/subscribeToEvents.go b/http-gateway/service/subscribeToEvents.go index 3f4edb6f7..9cfe1588b 100644 --- a/http-gateway/service/subscribeToEvents.go +++ b/http-gateway/service/subscribeToEvents.go @@ -28,7 +28,7 @@ func modifyResourceIdFilter(data []byte) []byte { resourceIdFilter := gjson.Get(string(data), "createSubscription.resourceIdFilter") newData := string(data) // append resourceIdFilter to httpResourceIdFilter - resourceIdFilter.ForEach(func(key, value gjson.Result) bool { + resourceIdFilter.ForEach(func(_, value gjson.Result) bool { newData, _ = sjson.Set(newData, "createSubscription.httpResourceIdFilter.-1", value.Str) return true }) diff --git a/http-gateway/service/subscribeToEvents_test.go b/http-gateway/service/subscribeToEvents_test.go index 7d9600db2..d284a2438 100644 --- a/http-gateway/service/subscribeToEvents_test.go +++ b/http-gateway/service/subscribeToEvents_test.go @@ -79,7 +79,7 @@ func (u *updateChecker) checkUpdateLightResource(ctx context.Context, t *testing expectedEvent := &pb.Event{ SubscriptionId: u.subUpdatedID, Type: &pb.Event_ResourceUpdatePending{ - ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, u.deviceID, test.TestResourceLightInstanceHref("1"), updCorrelationID, + ResourceUpdatePending: pbTest.MakeResourceUpdatePending(t, u.deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, updCorrelationID, map[string]interface{}{ "power": power, }), @@ -91,7 +91,7 @@ func (u *updateChecker) checkUpdateLightResource(ctx context.Context, t *testing expectedEvent := &pb.Event{ SubscriptionId: u.subUpdatedID, Type: &pb.Event_ResourceUpdated{ - ResourceUpdated: pbTest.MakeResourceUpdated(t, u.deviceID, test.TestResourceLightInstanceHref("1"), updCorrelationID, nil), + ResourceUpdated: pbTest.MakeResourceUpdated(t, u.deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, updCorrelationID, nil), }, CorrelationId: "updatePending + resourceUpdated", } @@ -100,7 +100,7 @@ func (u *updateChecker) checkUpdateLightResource(ctx context.Context, t *testing expectedEvent := &pb.Event{ SubscriptionId: u.baseSubID, Type: &pb.Event_ResourceChanged{ - ResourceChanged: pbTest.MakeResourceChanged(t, u.deviceID, test.TestResourceLightInstanceHref("1"), + ResourceChanged: pbTest.MakeResourceChanged(t, u.deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, ev.GetResourceChanged().GetAuditContext().GetCorrelationId(), map[string]interface{}{ "state": false, @@ -134,7 +134,7 @@ func testRequestHandlerSubscribeToEvents(t *testing.T, deviceID string, resource shutdownHttp := httpgwTest.SetUp(t) defer shutdownHttp() - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -160,30 +160,30 @@ func testRequestHandlerSubscribeToEvents(t *testing.T, deviceID string, resource send := func(req *pb.SubscribeToEvents) error { marshaler := runtime.JSONPb{} - data, err := marshaler.Marshal(req) - require.NoError(t, err) + data, errM := marshaler.Marshal(req) + require.NoError(t, errM) return wsConn.WriteMessage(websocket.TextMessage, data) } sendBackwardResourceIDFilter := func(req *pb.SubscribeToEvents, resourceIDFilter []string) error { marshaler := runtime.JSONPb{} - data, err := marshaler.Marshal(req) - require.NoError(t, err) + data, errM := marshaler.Marshal(req) + require.NoError(t, errM) - newData, err := sjson.Delete(string(data), "createSubscription.resourceIdFilter") - require.NoError(t, err) - newData, err = sjson.Set(newData, "createSubscription.resourceIdFilter", resourceIDFilter) - require.NoError(t, err) + newData, errM := sjson.Delete(string(data), "createSubscription.resourceIdFilter") + require.NoError(t, errM) + newData, errM = sjson.Set(newData, "createSubscription.resourceIdFilter", resourceIDFilter) + require.NoError(t, errM) return wsConn.WriteMessage(websocket.TextMessage, []byte(newData)) } recv := func() (*pb.Event, error) { - _, reader, err := wsConn.NextReader() - if err != nil { - return nil, err + _, reader, errM := wsConn.NextReader() + if errM != nil { + return nil, errM } var event pb.Event - err = httpgwTest.Unmarshal(http.StatusOK, reader, &event) - return &event, err + errM = httpgwTest.Unmarshal(http.StatusOK, reader, &event) + return &event, errM } createResourceSub := &pb.SubscribeToEvents{ CorrelationId: "testToken", @@ -212,7 +212,7 @@ func testRequestHandlerSubscribeToEvents(t *testing.T, deviceID string, resource ev, err := recv() require.NoError(t, err) expectedEvent := &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: &pb.Event_OperationProcessed_{ OperationProcessed: &pb.Event_OperationProcessed{ ErrorStatus: &pb.Event_OperationProcessed_ErrorStatus{ @@ -223,7 +223,7 @@ func testRequestHandlerSubscribeToEvents(t *testing.T, deviceID string, resource CorrelationId: "testToken", } pbTest.CmpEvent(t, expectedEvent, ev, "") - baseSubID := ev.SubscriptionId + baseSubID := ev.GetSubscriptionId() deviceID, shutdownDevSim := test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) @@ -269,7 +269,7 @@ func testRequestHandlerSubscribeToEvents(t *testing.T, deviceID string, resource ev, err = recv() require.NoError(t, err) expectedEvent = &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: &pb.Event_OperationProcessed_{ OperationProcessed: &pb.Event_OperationProcessed{ ErrorStatus: &pb.Event_OperationProcessed_ErrorStatus{ @@ -285,7 +285,7 @@ func testRequestHandlerSubscribeToEvents(t *testing.T, deviceID string, resource c: c, deviceID: deviceID, baseSubID: baseSubID, - subUpdatedID: ev.SubscriptionId, + subUpdatedID: ev.GetSubscriptionId(), recv: recv, } updChecker.checkUpdateLightResource(ctx, t, 99) @@ -308,7 +308,7 @@ func testRequestHandlerSubscribeToEvents(t *testing.T, deviceID string, resource ev, err = recv() require.NoError(t, err) expectedEvent = &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: &pb.Event_OperationProcessed_{ OperationProcessed: &pb.Event_OperationProcessed{ ErrorStatus: &pb.Event_OperationProcessed_ErrorStatus{ @@ -319,7 +319,7 @@ func testRequestHandlerSubscribeToEvents(t *testing.T, deviceID string, resource CorrelationId: "receivePending + resourceReceived", } pbTest.CmpEvent(t, expectedEvent, ev, "") - subReceivedID := ev.SubscriptionId + subReceivedID := ev.GetSubscriptionId() _, err = c.GetResourceFromDevice(ctx, &pb.GetResourceFromDeviceRequest{ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), @@ -331,8 +331,9 @@ func testRequestHandlerSubscribeToEvents(t *testing.T, deviceID string, resource SubscriptionId: subReceivedID, Type: &pb.Event_ResourceRetrievePending{ ResourceRetrievePending: &events.ResourceRetrievePending{ - ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), - AuditContext: ev.GetResourceRetrievePending().GetAuditContext(), + ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), + AuditContext: ev.GetResourceRetrievePending().GetAuditContext(), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, }, CorrelationId: "receivePending + resourceReceived", @@ -345,7 +346,7 @@ func testRequestHandlerSubscribeToEvents(t *testing.T, deviceID string, resource expectedEvent = &pb.Event{ SubscriptionId: subReceivedID, Type: &pb.Event_ResourceRetrieved{ - ResourceRetrieved: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), recvCorrelationID, + ResourceRetrieved: pbTest.MakeResourceRetrieved(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, recvCorrelationID, map[string]interface{}{ "name": "Light", "power": 0x0, @@ -367,7 +368,7 @@ func testRequestHandlerSubscribeToEvents(t *testing.T, deviceID string, resource if ev.GetDeviceUnregistered() != nil { expectedEvent = &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), Type: &pb.Event_DeviceUnregistered_{ DeviceUnregistered: &pb.Event_DeviceUnregistered{ DeviceIds: []string{deviceID}, diff --git a/http-gateway/service/updateDeviceMetadata_test.go b/http-gateway/service/updateDeviceMetadata_test.go index 9566dad49..12437af39 100644 --- a/http-gateway/service/updateDeviceMetadata_test.go +++ b/http-gateway/service/updateDeviceMetadata_test.go @@ -127,7 +127,7 @@ func TestRequestHandlerUpdateDeviceMetadata(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -163,8 +163,8 @@ func TestRequestHandlerUpdateDeviceMetadata(t *testing.T) { }() updateDeviceTwinSynchronization := func(in *pb.UpdateDeviceMetadataRequest) error { - data, err := protojson.Marshal(in) - require.NoError(t, err) + data, errM := protojson.Marshal(in) + require.NoError(t, errM) rb := httpgwTest.NewRequest(http.MethodPut, uri.DeviceMetadata, bytes.NewReader(data)).AuthToken(token).DeviceId(deviceID) resp := httpgwTest.HTTPDo(t, rb.Build()) @@ -173,8 +173,8 @@ func TestRequestHandlerUpdateDeviceMetadata(t *testing.T) { }(resp) var got pb.UpdateDeviceMetadataResponse - err = httpgwTest.Unmarshal(resp.StatusCode, resp.Body, &got) - return err + errM = httpgwTest.Unmarshal(resp.StatusCode, resp.Body, &got) + return errM } err = updateDeviceTwinSynchronization(&pb.UpdateDeviceMetadataRequest{ diff --git a/http-gateway/service/updateResource.go b/http-gateway/service/updateResource.go index 332930a18..e47c06cbf 100644 --- a/http-gateway/service/updateResource.go +++ b/http-gateway/service/updateResource.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/http" + "net/http/httptest" "github.com/gorilla/mux" "github.com/plgd-dev/go-coap/v3/message" @@ -53,5 +54,14 @@ func (requestHandler *RequestHandler) updateResource(w http.ResponseWriter, r *h } r.Body = newBody - requestHandler.mux.ServeHTTP(w, r) + rec := httptest.NewRecorder() + onlyContent := r.URL.Query().Get(uri.OnlyContentQueryKey) + requestHandler.mux.ServeHTTP(rec, r) + allowEmptyContent := false + if parseBoolQuery(onlyContent) { + allowEmptyContent = requestHandler.filterOnlyContent(rec, "data", "content") + } + toSimpleResponse(w, rec, allowEmptyContent, func(w http.ResponseWriter, err error) { + serverMux.WriteError(w, kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "cannot update resource('/%v%v') from the device: %v", deviceID, href, err)) + }, streamResponseKey) } diff --git a/http-gateway/service/updateResource_test.go b/http-gateway/service/updateResource_test.go index c22997670..19609f3e9 100644 --- a/http-gateway/service/updateResource_test.go +++ b/http-gateway/service/updateResource_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/plgd-dev/device/v2/pkg/codec/json" "github.com/plgd-dev/device/v2/schema/device" "github.com/plgd-dev/device/v2/schema/interfaces" "github.com/plgd-dev/go-coap/v3/message" @@ -38,6 +39,7 @@ func TestRequestHandlerUpdateResourcesValues(t *testing.T) { deviceID string resourceHref string resourceInterface string + onlyContent bool resourceData interface{} ttl time.Duration } @@ -54,6 +56,7 @@ func TestRequestHandlerUpdateResourcesValues(t *testing.T) { accept: uri.ApplicationProtoJsonContentType, deviceID: deviceID, resourceHref: "/unknown", + onlyContent: true, }, wantErr: true, wantHTTPCode: http.StatusNotFound, @@ -100,7 +103,7 @@ func TestRequestHandlerUpdateResourcesValues(t *testing.T) { "power": 1, }, }, - want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), "", nil), + want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", nil), wantHTTPCode: http.StatusOK, }, { @@ -114,7 +117,7 @@ func TestRequestHandlerUpdateResourcesValues(t *testing.T) { "power": 102, }, }, - want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), "", nil), + want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", nil), wantHTTPCode: http.StatusOK, }, { @@ -128,7 +131,7 @@ func TestRequestHandlerUpdateResourcesValues(t *testing.T) { }, resourceInterface: interfaces.OC_IF_BASELINE, }, - want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), "", nil), + want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", nil), wantHTTPCode: http.StatusOK, }, { @@ -142,7 +145,7 @@ func TestRequestHandlerUpdateResourcesValues(t *testing.T) { }, resourceInterface: interfaces.OC_IF_BASELINE, }, - want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), "", nil), + want: pbTest.MakeResourceUpdated(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", nil), wantHTTPCode: http.StatusOK, }, { @@ -168,7 +171,8 @@ func TestRequestHandlerUpdateResourcesValues(t *testing.T) { "value": true, }), }, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: test.TestResourceSwitchesInstanceResourceTypes, }, wantHTTPCode: http.StatusOK, }, @@ -186,7 +190,7 @@ func TestRequestHandlerUpdateResourcesValues(t *testing.T) { token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -210,7 +214,7 @@ func TestRequestHandlerUpdateResourcesValues(t *testing.T) { require.NoError(t, err) rb := httpgwTest.NewRequest(http.MethodPut, uri.AliasDeviceResource, bytes.NewReader(data)).AuthToken(token).Accept(tt.args.accept) rb.DeviceId(tt.args.deviceID).ResourceHref(tt.args.resourceHref).ResourceInterface(tt.args.resourceInterface).ContentType(tt.args.contentType) - rb.AddTimeToLive(tt.args.ttl) + rb.AddTimeToLive(tt.args.ttl).OnlyContent(tt.args.onlyContent) resp := httpgwTest.HTTPDo(t, rb.Build()) defer func() { _ = resp.Body.Close() @@ -228,3 +232,104 @@ func TestRequestHandlerUpdateResourcesValues(t *testing.T) { }) } } + +func TestRequestHandlerUpdateResourcesValuesWithOnlyContent(t *testing.T) { + deviceID := test.MustFindDeviceByName(test.TestDeviceName) + switchID := "1" + type args struct { + accept string + contentType string + deviceID string + resourceHref string + resourceData interface{} + } + tests := []struct { + name string + args args + want interface{} + wantErr bool + wantHTTPCode int + }{ + { + name: "valid - accept " + uri.ApplicationProtoJsonContentType, + args: args{ + accept: uri.ApplicationProtoJsonContentType, + contentType: message.AppJSON.String(), + deviceID: deviceID, + resourceHref: test.TestResourceLightInstanceHref("1"), + resourceData: map[string]interface{}{ + "power": 102, + }, + }, + want: nil, + wantHTTPCode: http.StatusOK, + }, + { + name: "revert-update - accept empty", + args: args{ + contentType: message.AppJSON.String(), + deviceID: deviceID, + resourceHref: test.TestResourceLightInstanceHref("1"), + resourceData: map[string]interface{}{ + "power": 0, + }, + }, + want: nil, + wantHTTPCode: http.StatusOK, + }, + } + + ctx, cancel := context.WithTimeout(context.Background(), config.TEST_TIMEOUT) + defer cancel() + + tearDown := service.SetUp(ctx, t) + defer tearDown() + + shutdownHttp := httpgwTest.SetUp(t) + defer shutdownHttp() + + token := oauthTest.GetDefaultAccessToken(t) + ctx = kitNetGrpc.CtxWithToken(ctx, token) + + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + RootCAs: test.GetRootCertificatePool(t), + }))) + require.NoError(t, err) + defer func() { + _ = conn.Close() + }() + c := pb.NewGrpcGatewayClient(conn) + + _, shutdownDevSim := test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, test.GetAllBackendResourceLinks()) + defer shutdownDevSim() + + test.AddDeviceSwitchResources(ctx, t, deviceID, c, switchID) + time.Sleep(200 * time.Millisecond) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + data, err := httpgwTest.GetContentData(&pb.Content{ + Data: test.EncodeToCbor(t, tt.args.resourceData), + ContentType: message.AppOcfCbor.String(), + }, tt.args.contentType) + require.NoError(t, err) + rb := httpgwTest.NewRequest(http.MethodPut, uri.AliasDeviceResource, bytes.NewReader(data)).AuthToken(token).Accept(tt.args.accept) + rb.DeviceId(tt.args.deviceID).ResourceHref(tt.args.resourceHref).ContentType(tt.args.contentType) + rb.OnlyContent(true) + resp := httpgwTest.HTTPDo(t, rb.Build()) + defer func() { + _ = resp.Body.Close() + }() + assert.Equal(t, tt.wantHTTPCode, resp.StatusCode) + + var got interface{} + err = json.ReadFrom(resp.Body, &got) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/http-gateway/swagger.wot.yaml b/http-gateway/swagger.wot.yaml new file mode 100644 index 000000000..ca7386796 --- /dev/null +++ b/http-gateway/swagger.wot.yaml @@ -0,0 +1,970 @@ +openapi: 3.1.0 +info: + title: plgd HTTP Gateway + version: 2.7.19 +servers: + - url: "https://try.plgd.cloud" +paths: + "/api/v1/things": + get: + tags: + - "Web of Things" + summary: "Retrieve Hub Thing Description" + description: | + Retrieve the description of the PLGD hub, including links to all associated things. + responses: + 200: + description: "Thing description of the plgd hub." + content: + application/json: + schema: + $ref: "#/components/schemas/thing" +components: + schemas: + anyUri: + type: string + description: + type: string + descriptions: + type: object + additionalProperties: + type: string + title: + type: string + titles: + type: object + additionalProperties: + type: string + security: + oneOf: + - type: array + items: + type: string + minItems: 1 + - type: string + scopes: + oneOf: + - type: array + items: + type: string + - type: string + subprotocol: + type: string + examples: + - longpoll + - websub + - sse + thing-context-td-uri-v1: + type: string + const: https://www.w3.org/2019/wot/td/v1 + thing-context-td-uri-v1.1: + type: string + const: https://www.w3.org/2022/wot/td/v1.1 + thing-context-td-uri-temp: + type: string + const: http://www.w3.org/ns/td + thing-context: + anyOf: + - $comment: New context URI with other vocabularies after it but not the old one + type: array + items: + - $ref: '#/components/schemas/thing-context-td-uri-v1.1' + additionalItems: + anyOf: + - $ref: '#/components/schemas/anyUri' + - type: object + not: + $ref: '#/components/schemas/thing-context-td-uri-v1' + - $comment: Only the new context URI + $ref: '#/components/schemas/thing-context-td-uri-v1.1' + - $comment: >- + Old context URI, followed by the new one and possibly other + vocabularies. minItems and contains are required since prefixItems + does not say all items should be provided + type: array + prefixItems: + - $ref: '#/components/schemas/thing-context-td-uri-v1' + - $ref: '#/components/schemas/thing-context-td-uri-v1.1' + minItems: 2 + contains: + $ref: '#/components/schemas/thing-context-td-uri-v1.1' + additionalItems: + anyOf: + - $ref: '#/components/schemas/anyUri' + - type: object + - $comment: >- + Old context URI, followed by possibly other vocabularies. minItems and + contains are required since prefixItems does not say all items should + be provided + type: array + prefixItems: + - $ref: '#/components/schemas/thing-context-td-uri-v1' + minItems: 1 + contains: + $ref: '#/components/schemas/thing-context-td-uri-v1' + additionalItems: + anyOf: + - $ref: '#/components/schemas/anyUri' + - type: object + - $comment: Only the old context URI + $ref: '#/components/schemas/thing-context-td-uri-v1' + bcp47_string: + type: string + pattern: >- + ^(((([A-Za-z]{2,3}(-([A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-([A-Za-z]{4}))?(-([A-Za-z]{2}|[0-9]{3}))?(-([A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-([0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(x(-[A-Za-z0-9]{1,8})+))?)|(x(-[A-Za-z0-9]{1,8})+)|((en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)))$ + type_declaration: + oneOf: + - type: string + not: + const: tm:ThingModel + - type: array + items: + type: string + not: + const: tm:ThingModel + dataSchema-type: + type: string + enum: + - boolean + - integer + - number + - string + - object + - array + - 'null' + dataSchema: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + title: + $ref: '#/components/schemas/title' + descriptions: + $ref: '#/components/schemas/descriptions' + titles: + $ref: '#/components/schemas/titles' + writeOnly: + type: boolean + readOnly: + type: boolean + oneOf: + type: array + items: + $ref: '#/components/schemas/dataSchema' + unit: + type: string + enum: + type: array + minItems: 1 + uniqueItems: true + format: + type: string + const: {} + default: {} + contentEncoding: + type: string + contentMediaType: + type: string + type: + $ref: '#/components/schemas/dataSchema-type' + items: + oneOf: + - $ref: '#/components/schemas/dataSchema' + - type: array + items: + $ref: '#/components/schemas/dataSchema' + maxItems: + type: integer + minimum: 0 + minItems: + type: integer + minimum: 0 + minimum: + type: number + maximum: + type: number + exclusiveMinimum: + type: number + exclusiveMaximum: + type: number + minLength: + type: integer + minimum: 0 + maxLength: + type: integer + minimum: 0 + multipleOf: + $ref: '#/components/schemas/multipleOfDefinition' + properties: + additionalProperties: + $ref: '#/components/schemas/dataSchema' + required: + type: array + items: + type: string + additionalResponsesDefinition: + type: array + items: + type: object + properties: + contentType: + type: string + schema: + type: string + success: + type: boolean + multipleOfDefinition: + type: + - integer + - number + exclusiveMinimum: 0 + expectedResponse: + type: object + properties: + contentType: + type: string + required: + - contentType + form_element_base: + type: object + properties: + op: + oneOf: + - type: string + - type: array + items: + type: string + href: + $ref: '#/components/schemas/anyUri' + contentType: + type: string + contentCoding: + type: string + subprotocol: + $ref: '#/components/schemas/subprotocol' + security: + $ref: '#/components/schemas/security' + scopes: + $ref: '#/components/schemas/scopes' + response: + $ref: '#/components/schemas/expectedResponse' + additionalResponses: + $ref: '#/components/schemas/additionalResponsesDefinition' + required: + - href + additionalProperties: true + form_element_property: + allOf: + - $ref: '#/components/schemas/form_element_base' + type: object + properties: + op: + oneOf: + - type: string + enum: + - readproperty + - writeproperty + - observeproperty + - unobserveproperty + - type: array + items: + type: string + enum: + - readproperty + - writeproperty + - observeproperty + - unobserveproperty + minItems: 1 + additionalProperties: true + form_element_action: + allOf: + - $ref: '#/components/schemas/form_element_base' + type: object + properties: + op: + oneOf: + - type: string + enum: + - invokeaction + - queryaction + - cancelaction + - type: array + items: + type: string + enum: + - invokeaction + - queryaction + - cancelaction + minItems: 1 + additionalProperties: true + form_element_event: + allOf: + - $ref: '#/components/schemas/form_element_base' + type: object + properties: + op: + oneOf: + - type: string + enum: + - subscribeevent + - unsubscribeevent + - type: array + items: + type: string + enum: + - subscribeevent + - unsubscribeevent + minItems: 1 + additionalProperties: true + form_element_root: + allOf: + - $ref: '#/components/schemas/form_element_base' + type: object + properties: + op: + oneOf: + - type: string + enum: + - readallproperties + - writeallproperties + - readmultipleproperties + - writemultipleproperties + - observeallproperties + - unobserveallproperties + - queryallactions + - subscribeallevents + - unsubscribeallevents + - type: array + items: + type: string + enum: + - readallproperties + - writeallproperties + - readmultipleproperties + - writemultipleproperties + - observeallproperties + - unobserveallproperties + - queryallactions + - subscribeallevents + - unsubscribeallevents + minItems: 1 + additionalProperties: true + required: + - op + form: + $comment: >- + This is NOT for validation purposes but for automatic generation of TS + types. For more info, please see: + https://github.com/w3c/wot-thing-description/pull/1319#issuecomment-994950057 + oneOf: + - $ref: '#/components/schemas/form_element_property' + - $ref: '#/components/schemas/form_element_action' + - $ref: '#/components/schemas/form_element_event' + - $ref: '#/components/schemas/form_element_root' + property_element: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + title: + $ref: '#/components/schemas/title' + titles: + $ref: '#/components/schemas/titles' + forms: + type: array + minItems: 1 + items: + $ref: '#/components/schemas/form_element_property' + uriVariables: + type: object + additionalProperties: + $ref: '#/components/schemas/dataSchema' + observable: + type: boolean + writeOnly: + type: boolean + readOnly: + type: boolean + oneOf: + type: array + items: + $ref: '#/components/schemas/dataSchema' + unit: + type: string + enum: + type: array + minItems: 1 + uniqueItems: true + format: + type: string + const: {} + default: {} + type: + $ref: '#/components/schemas/dataSchema-type' + items: + oneOf: + - $ref: '#/components/schemas/dataSchema' + - type: array + items: + $ref: '#/components/schemas/dataSchema' + maxItems: + type: integer + minimum: 0 + minItems: + type: integer + minimum: 0 + minimum: + type: number + maximum: + type: number + exclusiveMinimum: + type: number + exclusiveMaximum: + type: number + minLength: + type: integer + minimum: 0 + maxLength: + type: integer + minimum: 0 + multipleOf: + $ref: '#/components/schemas/multipleOfDefinition' + properties: + additionalProperties: + $ref: '#/components/schemas/dataSchema' + required: + type: array + items: + type: string + required: + - forms + additionalProperties: true + action_element: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + title: + $ref: '#/components/schemas/title' + titles: + $ref: '#/components/schemas/titles' + forms: + type: array + minItems: 1 + items: + $ref: '#/components/schemas/form_element_action' + uriVariables: + type: object + additionalProperties: + $ref: '#/components/schemas/dataSchema' + input: + $ref: '#/components/schemas/dataSchema' + output: + $ref: '#/components/schemas/dataSchema' + safe: + type: boolean + idempotent: + type: boolean + synchronous: + type: boolean + required: + - forms + additionalProperties: true + event_element: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + title: + $ref: '#/components/schemas/title' + titles: + $ref: '#/components/schemas/titles' + forms: + type: array + minItems: 1 + items: + $ref: '#/components/schemas/form_element_event' + uriVariables: + type: object + additionalProperties: + $ref: '#/components/schemas/dataSchema' + subscription: + $ref: '#/components/schemas/dataSchema' + data: + $ref: '#/components/schemas/dataSchema' + dataResponse: + $ref: '#/components/schemas/dataSchema' + cancellation: + $ref: '#/components/schemas/dataSchema' + required: + - forms + additionalProperties: true + base_link_element: + type: object + properties: + href: + $ref: '#/components/schemas/anyUri' + type: + type: string + rel: + type: string + anchor: + $ref: '#/components/schemas/anyUri' + hreflang: + anyOf: + - $ref: '#/components/schemas/bcp47_string' + - type: array + items: + $ref: '#/components/schemas/bcp47_string' + required: + - href + additionalProperties: true + link_element: + allOf: + - $ref: '#/components/schemas/base_link_element' + - not: + description: A basic link element should not contain sizes + type: object + properties: + sizes: {} + required: + - sizes + - not: + description: A basic link element should not contain icon or tm:extends + properties: + rel: + enum: + - icon + - tm:extends + required: + - rel + icon_link_element: + allOf: + - $ref: '#/components/schemas/base_link_element' + - properties: + rel: + const: icon + sizes: + type: string + pattern: '[0-9]*x[0-9]+' + required: + - rel + additionalSecurityScheme: + description: >- + Applies to additional SecuritySchemes not defined in the WoT TD + specification. + $comment: >- + Additional SecuritySchemes should always be defined via a context + extension, using a prefixed value for the scheme. This prefix (e.g. 'ace', + see the example below) must contain at least one character in order to + reference a valid JSON-LD context extension. + examples: + - scheme: ace:ACESecurityScheme + ace:as: coaps://as.example.com/token + ace:audience: coaps://rs.example.com + ace:scopes: + - limited + - special + ace:cnonce: true + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + proxy: + $ref: '#/components/schemas/anyUri' + scheme: + type: string + pattern: .+:.* + required: + - scheme + additionalProperties: true + noSecurityScheme: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + proxy: + $ref: '#/components/schemas/anyUri' + scheme: + type: string + enum: + - nosec + required: + - scheme + additionalProperties: true + autoSecurityScheme: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + proxy: + $ref: '#/components/schemas/anyUri' + scheme: + type: string + enum: + - auto + not: + required: + - name + required: + - scheme + additionalProperties: true + comboSecurityScheme: + oneOf: + - type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + proxy: + $ref: '#/components/schemas/anyUri' + scheme: + type: string + enum: + - combo + oneOf: + type: array + minItems: 2 + items: + type: string + required: + - scheme + - oneOf + additionalProperties: true + - type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + proxy: + $ref: '#/components/schemas/anyUri' + scheme: + type: string + enum: + - combo + allOf: + type: array + minItems: 2 + items: + type: string + required: + - scheme + - allOf + additionalProperties: true + basicSecurityScheme: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + proxy: + $ref: '#/components/schemas/anyUri' + scheme: + type: string + enum: + - basic + in: + type: string + enum: + - header + - query + - body + - cookie + - auto + name: + type: string + required: + - scheme + additionalProperties: true + digestSecurityScheme: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + proxy: + $ref: '#/components/schemas/anyUri' + scheme: + type: string + enum: + - digest + qop: + type: string + enum: + - auth + - auth-int + in: + type: string + enum: + - header + - query + - body + - cookie + - auto + name: + type: string + required: + - scheme + additionalProperties: true + apiKeySecurityScheme: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + proxy: + $ref: '#/components/schemas/anyUri' + scheme: + type: string + enum: + - apikey + in: + type: string + enum: + - header + - query + - body + - cookie + - uri + - auto + name: + type: string + required: + - scheme + additionalProperties: true + bearerSecurityScheme: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + proxy: + $ref: '#/components/schemas/anyUri' + scheme: + type: string + enum: + - bearer + authorization: + $ref: '#/components/schemas/anyUri' + alg: + type: string + format: + type: string + in: + type: string + enum: + - header + - query + - body + - cookie + - auto + name: + type: string + required: + - scheme + additionalProperties: true + pskSecurityScheme: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + proxy: + $ref: '#/components/schemas/anyUri' + scheme: + type: string + enum: + - psk + identity: + type: string + required: + - scheme + additionalProperties: true + oAuth2SecurityScheme: + type: object + properties: + '@type': + $ref: '#/components/schemas/type_declaration' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + proxy: + $ref: '#/components/schemas/anyUri' + scheme: + type: string + enum: + - oauth2 + authorization: + $ref: '#/components/schemas/anyUri' + token: + $ref: '#/components/schemas/anyUri' + refresh: + $ref: '#/components/schemas/anyUri' + scopes: + oneOf: + - type: array + items: + type: string + - type: string + flow: + anyOf: + - type: string + - type: string + enum: + - code + - client + required: + - scheme + additionalProperties: true + securityScheme: + oneOf: + - $ref: '#/components/schemas/noSecurityScheme' + - $ref: '#/components/schemas/autoSecurityScheme' + - $ref: '#/components/schemas/comboSecurityScheme' + - $ref: '#/components/schemas/basicSecurityScheme' + - $ref: '#/components/schemas/digestSecurityScheme' + - $ref: '#/components/schemas/apiKeySecurityScheme' + - $ref: '#/components/schemas/bearerSecurityScheme' + - $ref: '#/components/schemas/pskSecurityScheme' + - $ref: '#/components/schemas/oAuth2SecurityScheme' + - $ref: '#/components/schemas/additionalSecurityScheme' + thing: + type: object + properties: + id: + type: string + format: uri + title: + $ref: '#/components/schemas/title' + titles: + $ref: '#/components/schemas/titles' + properties: + type: object + additionalProperties: + $ref: '#/components/schemas/property_element' + actions: + type: object + additionalProperties: + $ref: '#/components/schemas/action_element' + events: + type: object + additionalProperties: + $ref: '#/components/schemas/event_element' + description: + $ref: '#/components/schemas/description' + descriptions: + $ref: '#/components/schemas/descriptions' + version: + type: object + properties: + instance: + type: string + required: + - instance + links: + type: array + items: + oneOf: + - $ref: '#/components/schemas/link_element' + - $ref: '#/components/schemas/icon_link_element' + forms: + type: array + minItems: 1 + items: + $ref: '#/components/schemas/form_element_root' + base: + $ref: '#/components/schemas/anyUri' + securityDefinitions: + type: object + minProperties: 1 + additionalProperties: + $ref: '#/components/schemas/securityScheme' + schemaDefinitions: + type: object + minProperties: 1 + additionalProperties: + $ref: '#/components/schemas/dataSchema' + support: + $ref: '#/components/schemas/anyUri' + created: + type: string + format: date-time + modified: + type: string + format: date-time + profile: + oneOf: + - $ref: '#/components/schemas/anyUri' + - type: array + minItems: 1 + items: + $ref: '#/components/schemas/anyUri' + security: + oneOf: + - type: string + - type: array + minItems: 1 + items: + type: string + uriVariables: + type: object + additionalProperties: + $ref: '#/components/schemas/dataSchema' + '@type': + $ref: '#/components/schemas/type_declaration' + '@context': + $ref: '#/components/schemas/thing-context' + required: + - title + - security + - securityDefinitions + - '@context' + additionalProperties: true diff --git a/http-gateway/swagger.yaml b/http-gateway/swagger.yaml index fd7cdc5a2..72329ff07 100644 --- a/http-gateway/swagger.yaml +++ b/http-gateway/swagger.yaml @@ -19,6 +19,40 @@ paths: application/json: schema: $ref: "#/components/schemas/HubConfiguration" + "/api/v1/things": + get: + tags: + - "Web of Things" + summary: "Retrieve Hub Thing Description" + description: | + Retrieve the description of the PLGD hub, including links to all associated things. + responses: + 200: + description: "Thing description of the plgd hub." + content: + application/json: + schema: + $ref: "https://raw.githubusercontent.com/plgd-dev/hub/main/http-gateway/swagger.wot.yaml#/components/schemas/thing" + 401: + $ref: "#/components/responses/unauthorized" + "/api/v1/things/{deviceId}": + get: + tags: + - "Web of Things" + summary: "Retrieve Device Thing Description" + description: | + Retrieve the thing description for a specific device. The device must be listed in the links of /api/v1/things. + parameters: + - $ref: "#/components/parameters/deviceId" + responses: + 200: + description: "Thing description of the device." + content: + application/json: + schema: + $ref: "https://raw.githubusercontent.com/plgd-dev/hub/main/http-gateway/swagger.wot.yaml#/components/schemas/thing" + 401: + $ref: "#/components/responses/unauthorized" "/api/v1/devices": get: tags: @@ -389,6 +423,7 @@ paths: - $ref: "#/components/parameters/shadow" - $ref: "#/components/parameters/timeToLive" - $ref: "#/components/parameters/etag" + - $ref: "#/components/parameters/onlyContent" responses: 200: description: "Resource content." @@ -419,6 +454,7 @@ paths: parameters: - $ref: "#/components/parameters/interface" - $ref: "#/components/parameters/timeToLive" + - $ref: "#/components/parameters/onlyContent" requestBody: description: "Updated content of the resource." content: @@ -961,6 +997,14 @@ components: type: string format: int64 description: "Unix timestamp in nanoseconds." + serviceId: + type: string + description: "The service.ID, which identify the device being served, must be set when the status is ONLINE. However, during an OFFLINE event, they will be sed to empty values." + localEndpoints: + type: array + description: "The last local endpoints of the device, and it is set when the status is ONLINE." + items: + type: string twinSynchronization: $ref: "#/components/schemas/TwinSynchronization" twinEnabled: @@ -1636,14 +1680,14 @@ components: title: "Visibility" deviceProvisioningService: type: string - title": "Address to device provisioning service HTTP API in format https://host:port" + title: "Address to device provisioning service HTTP API in format https://host:port" UIVisibility: type: object description: | true - show, false - hide properties: mainSidebar: - $ref: "#/definitions/UIVisibilityMainSidebar" + $ref: "#/components/schemas/UIVisibilityMainSidebar" title: "Main sidebar visibility" parameters: deviceId: @@ -1754,6 +1798,13 @@ components: schema: type: string format: base64 + onlyContent: + name: onlyContent + in: query + description: "Return only content of the resource in the response." + schema: + type: boolean + default: false responses: ok: description: Content is stored in body. diff --git a/http-gateway/test/http.go b/http-gateway/test/http.go index 8164c3055..ad47b5b3c 100644 --- a/http-gateway/test/http.go +++ b/http-gateway/test/http.go @@ -55,7 +55,7 @@ func (c *RequestBuilder) DeviceId(deviceID string) *RequestBuilder { } func (c *RequestBuilder) Twin(v bool) *RequestBuilder { - c.AddQuery(uri.TwinQueryKey, fmt.Sprintf("%v", v)) + c.AddQuery(uri.TwinQueryKey, strconv.FormatBool(v)) return c } @@ -63,7 +63,7 @@ func (c *RequestBuilder) Timestamp(v time.Time) *RequestBuilder { if v.IsZero() { return c } - c.AddQuery(uri.TimestampFilterQueryKey, fmt.Sprintf("%v", v.UnixNano())) + c.AddQuery(uri.TimestampFilterQueryKey, strconv.FormatInt(v.UnixNano(), 10)) return c } @@ -102,7 +102,7 @@ func (c *RequestBuilder) ResourceHref(resourceHref string) *RequestBuilder { } func (c *RequestBuilder) AuthToken(token string) *RequestBuilder { - c.header["Authorization"] = fmt.Sprintf("bearer %s", token) + c.header["Authorization"] = "bearer " + token return c } @@ -114,6 +114,11 @@ func (c *RequestBuilder) Accept(accept string) *RequestBuilder { return c } +func (c *RequestBuilder) OnlyContent(v bool) *RequestBuilder { + c.AddQuery(uri.OnlyContentQueryKey, strconv.FormatBool(v)) + return c +} + func (c *RequestBuilder) ContentType(contentType string) *RequestBuilder { if contentType == "" { return c diff --git a/http-gateway/test/pendingCommands.go b/http-gateway/test/pendingCommands.go index 81b1a6c10..0fe922f86 100644 --- a/http-gateway/test/pendingCommands.go +++ b/http-gateway/test/pendingCommands.go @@ -7,7 +7,7 @@ import ( ) func ToCommandsFilter(s []pb.GetPendingCommandsRequest_Command) []string { - var sf []string + sf := make([]string, 0, len(s)) for _, v := range s { sf = append(sf, strconv.FormatInt(int64(v), 10)) } diff --git a/http-gateway/test/test.go b/http-gateway/test/test.go index 2e7b7dd79..8c63f9714 100644 --- a/http-gateway/test/test.go +++ b/http-gateway/test/test.go @@ -2,6 +2,9 @@ package test import ( "context" + "encoding/json" + "io" + "net/http" "os" "sync" "time" @@ -11,7 +14,7 @@ import ( "github.com/plgd-dev/hub/v2/http-gateway/uri" "github.com/plgd-dev/hub/v2/pkg/fsnotify" "github.com/plgd-dev/hub/v2/pkg/log" - "github.com/plgd-dev/hub/v2/pkg/net/http" + pkgHttp "github.com/plgd-dev/hub/v2/pkg/net/http" "github.com/plgd-dev/hub/v2/test/config" testHttp "github.com/plgd-dev/hub/v2/test/http" "github.com/plgd-dev/kit/v2/codec/cbor" @@ -53,7 +56,7 @@ func MakeConfig(t require.TestingT, enableUI bool) service.Config { cfg.APIs.HTTP.Server = config.MakeHttpServerConfig() cfg.Clients.GrpcGateway.Connection = config.MakeGrpcClientConfig(config.GRPC_GW_HOST) - cfg.Clients.OpenTelemetryCollector = http.OpenTelemetryCollectorConfig{ + cfg.Clients.OpenTelemetryCollector = pkgHttp.OpenTelemetryCollectorConfig{ Config: config.MakeOpenTelemetryCollectorClient(), } @@ -111,3 +114,16 @@ func GetContentData(content *pb.Content, desiredContentType string) ([]byte, err } return []byte(v), err } + +func UnmarshalJson(code int, input io.Reader, v any) error { + var data json.RawMessage + err := json.NewDecoder(input).Decode(&data) + if err != nil { + return err + } + if code != http.StatusOK { + return UnmarshalError(data) + } + err = json.Unmarshal(data, v) + return err +} diff --git a/http-gateway/test/unmarshalProto.go b/http-gateway/test/unmarshalProto.go index 44e7a49a9..0d4318661 100644 --- a/http-gateway/test/unmarshalProto.go +++ b/http-gateway/test/unmarshalProto.go @@ -51,7 +51,7 @@ func Unmarshal(code int, input io.Reader, v protoreflect.ProtoMessage) error { u := protojson.UnmarshalOptions{ DiscardUnknown: true, } - err := u.Unmarshal(data, v) + err = u.Unmarshal(data, v) if err != nil { return err } diff --git a/http-gateway/uri/uri.go b/http-gateway/uri/uri.go index b20a5e6e8..54e53ab6f 100644 --- a/http-gateway/uri/uri.go +++ b/http-gateway/uri/uri.go @@ -21,6 +21,7 @@ const ( TimestampFilterQueryKey = "timestampFilter" CorrelationIdFilterQueryKey = "correlationIdFilter" ETagQueryKey = "etag" + OnlyContentQueryKey = "onlyContent" AliasInterfaceQueryKey = "interface" AliasCommandFilterQueryKey = "command" @@ -34,11 +35,13 @@ const ( AcceptHeaderKey = "Accept" ETagHeaderKey = "ETag" + DevicesPathKey = "devices" ResourcesPathKey = "resources" ResourceLinksPathKey = "resource-links" PendingCommandsPathKey = "pending-commands" PendingMetadataUpdatesPathKey = "pending-metadata-updates" EventsPathKey = "events" + ThingsPathKey = "things" ApplicationProtoJsonContentType = "application/protojson" @@ -53,6 +56,11 @@ const ( // web configuration for ui WebConfiguration = "/web_configuration.json" + // list devices with thing descriptions + Things = API + "/" + ThingsPathKey + // (HTTP ALIAS) GET /api/v1/things/{deviceId} + AliasDeviceThing = Things + "/{" + DeviceIDKey + "}" + // (GRPC + HTTP) GET /api/v1/devices -> rpc GetDevices // (GRPC + HTTP) DELETE /api/v1/devices -> rpc DeleteDevices Devices = API + "/devices" @@ -133,4 +141,5 @@ var QueryCaseInsensitive = map[string]string{ strings.ToLower(TimestampFilterQueryKey): TimestampFilterQueryKey, strings.ToLower(TimeToLiveQueryKey): TimeToLiveQueryKey, strings.ToLower(CorrelationIdFilterQueryKey): CorrelationIdFilterQueryKey, + strings.ToLower(OnlyContentQueryKey): OnlyContentQueryKey, } diff --git a/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/DevicesDetailsPage.tsx b/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/DevicesDetailsPage.tsx index 222cc871c..4bcc0a468 100644 --- a/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/DevicesDetailsPage.tsx +++ b/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/DevicesDetailsPage.tsx @@ -236,6 +236,7 @@ const DevicesDetailsPage: FC = (props) => { softwareUpdateData={softwareUpdateData?.result?.data?.content} twinSyncLoading={twinSyncLoading} types={data?.types} + endpoints={data?.metadata?.connection?.localEndpoints} /> ), }, diff --git a/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/Tabs/Tab1.tsx b/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/Tabs/Tab1.tsx index 508d0db23..69c45b69b 100644 --- a/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/Tabs/Tab1.tsx +++ b/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/Tabs/Tab1.tsx @@ -21,8 +21,19 @@ import DateFormat from '@/containers/PendingCommands/DateFormat' import testId from '@/testId' const Tab1: FC = (props) => { - const { isTwinEnabled, setTwinSynchronization, twinSyncLoading, deviceId, types, deviceName, model, pendingCommandsData, firmware, softwareUpdateData } = - props + const { + isTwinEnabled, + setTwinSynchronization, + twinSyncLoading, + deviceId, + types, + deviceName, + model, + pendingCommandsData, + firmware, + softwareUpdateData, + endpoints, + } = props const { formatMessage: _ } = useIntl() const resourceRegistrationObservationWSKey = getResourceRegistrationNotificationKey(deviceId) @@ -156,6 +167,22 @@ const Tab1: FC = (props) => { ), }, { attribute: _(t.status), value: pendingCommandsData ? `${pendingCommandsData.length} pending commands` : '-' }, + { + attribute: _(t.endpoints), + value: endpoints ? ( + + {endpoints?.map?.((endpoint: string) => {endpoint})} + + ) : ( +
-
+ ), + }, ]} /> diff --git a/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/Tabs/Tab1.types.ts b/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/Tabs/Tab1.types.ts index a82229bcb..fd020f3ae 100644 --- a/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/Tabs/Tab1.types.ts +++ b/http-gateway/web/src/containers/Devices/Detail/DevicesDetailsPage/Tabs/Tab1.types.ts @@ -20,4 +20,5 @@ export type Props = { purl: string // url with query parameters to update server signed: string // "vendor" } + endpoints?: string[] } diff --git a/http-gateway/web/src/containers/Devices/Devices.i18n.ts b/http-gateway/web/src/containers/Devices/Devices.i18n.ts index f4481918c..b4f4ea3be 100644 --- a/http-gateway/web/src/containers/Devices/Devices.i18n.ts +++ b/http-gateway/web/src/containers/Devices/Devices.i18n.ts @@ -565,4 +565,8 @@ export const messages = defineMessages({ id: 'devices.dps', defaultMessage: 'DPS', }, + endpoints: { + id: 'devices.endpoints', + defaultMessage: 'Endpoints', + }, }) diff --git a/http-gateway/web/src/containers/Devices/Devices.types.ts b/http-gateway/web/src/containers/Devices/Devices.types.ts index aabc69bf6..2621b8bad 100644 --- a/http-gateway/web/src/containers/Devices/Devices.types.ts +++ b/http-gateway/web/src/containers/Devices/Devices.types.ts @@ -26,6 +26,7 @@ export type DeviceDataType = { } connection?: { status?: string + localEndpoints?: string[] } twinEnabled?: boolean } diff --git a/identity-store/client/ownerCache.go b/identity-store/client/ownerCache.go index 7b440afbe..559cb6358 100644 --- a/identity-store/client/ownerCache.go +++ b/identity-store/client/ownerCache.go @@ -186,7 +186,7 @@ func (c *OwnerCache) getOwnerDevices(ctx context.Context, isClient pbIS.Identity if err != nil { return nil, status.Errorf(status.Convert(err).Code(), "cannot receive owners devices: %v", err) } - ownerDevices = append(ownerDevices, device.DeviceId) + ownerDevices = append(ownerDevices, device.GetDeviceId()) } return ownerDevices, nil } @@ -222,13 +222,13 @@ func (c *OwnerCache) Subscribe(owner string, onEvent func(e *events.Event)) (fun closeFunc = c.makeCloseFunc(owner, handlerID) } if s.subscription == nil { - err := s.subscribeLocked(owner, c.conn.Subscribe, func(msg *nats.Msg) { + errS := s.subscribeLocked(owner, c.conn.Subscribe, func(msg *nats.Msg) { if errH := s.Handle(msg); errH != nil { c.errFunc(errH) } }) - if err != nil { - return err + if errS != nil { + return errS } } return nil @@ -252,7 +252,6 @@ func (c *OwnerCache) Update(ctx context.Context) (added []string, removed []stri added, removed, err = s.syncDevicesLocked(ctx, owner, c) return err }) - if err != nil { return nil, nil, err } diff --git a/identity-store/client/ownerCache_test.go b/identity-store/client/ownerCache_test.go index 63e2e37f5..233ea169a 100644 --- a/identity-store/client/ownerCache_test.go +++ b/identity-store/client/ownerCache_test.go @@ -59,7 +59,7 @@ func TestOwnerCacheSubscribe(t *testing.T) { CertFile: cfg.APIs.GRPC.TLS.CertFile, KeyFile: cfg.APIs.GRPC.TLS.KeyFile, }, - }, fileWatcher, log.Get(), noop.NewTracerProvider(), grpc.WithPerRPCCredentials(kitNetGrpc.NewOAuthAccess(func(ctx context.Context) (*oauth2.Token, error) { + }, fileWatcher, log.Get(), noop.NewTracerProvider(), grpc.WithPerRPCCredentials(kitNetGrpc.NewOAuthAccess(func(context.Context) (*oauth2.Token, error) { return &oauth2.Token{ AccessToken: token, TokenType: "Bearer", @@ -127,7 +127,7 @@ func TestOwnerCacheSubscribe(t *testing.T) { time.Sleep(time.Millisecond * 100) for _, d := range devices[:2] { - _, err := c.AddDevice(ctx, &pb.AddDeviceRequest{DeviceId: d}) + _, err = c.AddDevice(ctx, &pb.AddDeviceRequest{DeviceId: d}) require.NoError(t, err) } time.Sleep(time.Millisecond * 100) @@ -171,7 +171,7 @@ func TestOwnerCacheSubscribe(t *testing.T) { DeviceIds: devices[:1], }) require.NoError(t, err) - assert.Equal(t, devices[:1], deleted.DeviceIds) + assert.Equal(t, devices[:1], deleted.GetDeviceIds()) // check update - after expiration time.Sleep(time.Millisecond * 100) // wait for synchronize the cache, so update doesn't change the cache diff --git a/identity-store/events/events.pb.go b/identity-store/events/events.pb.go index e98416df8..517181492 100644 --- a/identity-store/events/events.pb.go +++ b/identity-store/events/events.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: identity-store/pb/events.proto package events diff --git a/identity-store/pb/devices.pb.go b/identity-store/pb/devices.pb.go index 75616d284..3b1e1c31b 100644 --- a/identity-store/pb/devices.pb.go +++ b/identity-store/pb/devices.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: identity-store/pb/devices.proto package pb diff --git a/identity-store/pb/service_grpc.pb.go b/identity-store/pb/service_grpc.pb.go index 775249fbb..af1f50d9f 100644 --- a/identity-store/pb/service_grpc.pb.go +++ b/identity-store/pb/service_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc v5.26.1 // source: identity-store/pb/service.proto package pb diff --git a/identity-store/persistence/cqldb/persist.go b/identity-store/persistence/cqldb/persist.go index abc2f97b3..c4875c8e2 100644 --- a/identity-store/persistence/cqldb/persist.go +++ b/identity-store/persistence/cqldb/persist.go @@ -137,7 +137,7 @@ func (i *iterator) Close() { func (p *PersistenceTx) Persist(d *persistence.AuthorizedDevice) error { if d == nil { - return fmt.Errorf("cannot persist nil device") + return errors.New("cannot persist nil device") } if p.err != nil { return p.err diff --git a/identity-store/persistence/cqldb/persist_test.go b/identity-store/persistence/cqldb/persist_test.go index 713d10712..4aefa1071 100644 --- a/identity-store/persistence/cqldb/persist_test.go +++ b/identity-store/persistence/cqldb/persist_test.go @@ -11,7 +11,6 @@ import ( "github.com/plgd-dev/hub/v2/pkg/log" "github.com/plgd-dev/hub/v2/test" "github.com/plgd-dev/hub/v2/test/config" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace/noop" ) @@ -28,7 +27,7 @@ func newTestPersistence(t *testing.T) *cqldb.Store { Embedded: cfg, Table: "testDeviceOwnership", }, fileWatcher, log.Get(), noop.NewTracerProvider()) - assert.NoError(t, err) + require.NoError(t, err) p.AddCloseFunc(func() { errC := fileWatcher.Close() @@ -98,12 +97,12 @@ func TestPersistenceTxRetrieve(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got, ok, err := tx.Retrieve(tt.deviceID, tt.owner) if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equal(t, tt.want, got) - assert.Equal(t, tt.wantOk, ok) + require.Error(t, err) + return } + require.NoError(t, err) + require.Equal(t, tt.want, got) + require.Equal(t, tt.wantOk, ok) }) } } @@ -158,12 +157,12 @@ func TestPersistenceTxRetrieveByDevice(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got, ok, err := tx.RetrieveByDevice(tt.deviceID) if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equal(t, tt.want, got) - assert.Equal(t, tt.wantOk, ok) + require.Error(t, err) + return } + require.NoError(t, err) + require.Equal(t, tt.want, got) + require.Equal(t, tt.wantOk, ok) }) } } @@ -221,8 +220,8 @@ func TestPersistenceTxRetrieveByOwner(t *testing.T) { iter := tx.RetrieveByOwner(tt.owner) defer iter.Close() func() { - err := iter.Err() - require.NoError(t, err) + errC := iter.Err() + require.NoError(t, errC) }() var retrievedDevices []*persistence.AuthorizedDevice @@ -235,7 +234,7 @@ func TestPersistenceTxRetrieveByOwner(t *testing.T) { retrievedDevices = append(retrievedDevices, &device) } - assert.Equal(t, tt.devices, retrievedDevices) + require.Equal(t, tt.devices, retrievedDevices) }) } } @@ -322,10 +321,10 @@ func TestPersistenceTxPersist(t *testing.T) { } err = tx.Persist(tt.device) if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) + require.Error(t, err) + return } + require.NoError(t, err) }) } } diff --git a/identity-store/persistence/cqldb/store.go b/identity-store/persistence/cqldb/store.go index e4e75e3af..2c73504d9 100644 --- a/identity-store/persistence/cqldb/store.go +++ b/identity-store/persistence/cqldb/store.go @@ -15,7 +15,7 @@ import ( // Document const ( - // cqldbdb has all keys in in lowercase + // cqldbdb has all keys in lowercase ownerKey = "ownerkey" deviceIDKey = "deviceid" ) diff --git a/identity-store/persistence/mongodb/persist.go b/identity-store/persistence/mongodb/persist.go index b968151e0..893562f6c 100644 --- a/identity-store/persistence/mongodb/persist.go +++ b/identity-store/persistence/mongodb/persist.go @@ -211,7 +211,7 @@ func (p *PersistenceTx) Delete(deviceID, userID string) error { return err } if res.DeletedCount == 0 { - return fmt.Errorf("not found") + return errors.New("not found") } if err := p.tx.CommitTransaction(p.ctx); err != nil { return fmt.Errorf("cannot commit transaction: %w", err) diff --git a/identity-store/service/addDevice.go b/identity-store/service/addDevice.go index 46da8cc35..b4e9d72f6 100644 --- a/identity-store/service/addDevice.go +++ b/identity-store/service/addDevice.go @@ -90,13 +90,14 @@ func (s *Service) AddDevice(ctx context.Context, request *pb.AddDeviceRequest) ( return nil, log.LogAndReturnError(status.Errorf(codes.InvalidArgument, "cannot add device: %v", err)) } - if request.DeviceId == "" { + deviceID := request.GetDeviceId() + if deviceID == "" { return nil, log.LogAndReturnError(status.Errorf(codes.InvalidArgument, "cannot add device: invalid DeviceId")) } - dev, ok, err := tx.RetrieveByDevice(request.DeviceId) + dev, ok, err := tx.RetrieveByDevice(deviceID) if err != nil { - return nil, log.LogAndReturnError(status.Errorf(codes.Internal, "cannot add device %v: %v", request.DeviceId, err.Error())) + return nil, log.LogAndReturnError(status.Errorf(codes.Internal, "cannot add device %v: %v", deviceID, err.Error())) } if ok { if dev.Owner == owner { @@ -106,7 +107,7 @@ func (s *Service) AddDevice(ctx context.Context, request *pb.AddDeviceRequest) ( } d := persistence.AuthorizedDevice{ - DeviceID: request.DeviceId, + DeviceID: deviceID, Owner: owner, } @@ -114,7 +115,7 @@ func (s *Service) AddDevice(ctx context.Context, request *pb.AddDeviceRequest) ( return nil, log.LogAndReturnError(status.Errorf(codes.Internal, "cannot add device up: %v", err.Error())) } - s.publishDevicesRegistered(ctx, owner, userID, s.hubID, []string{request.DeviceId}) + s.publishDevicesRegistered(ctx, owner, userID, s.hubID, []string{deviceID}) return &pb.AddDeviceResponse{}, nil } diff --git a/identity-store/service/deleteDevices.go b/identity-store/service/deleteDevices.go index ef9a6193d..1347b7324 100644 --- a/identity-store/service/deleteDevices.go +++ b/identity-store/service/deleteDevices.go @@ -64,14 +64,14 @@ func (s *Service) publishDevicesUnregistered(ctx context.Context, owner, userID, func getDeviceIDs(request *pb.DeleteDevicesRequest, tx persistence.PersistenceTx, owner string) ([]string, error) { var deviceIds []string - if len(request.DeviceIds) == 0 { + if len(request.GetDeviceIds()) == 0 { var err error if deviceIds, err = getOwnerDevices(tx, owner); err != nil { return nil, status.Errorf(codes.InvalidArgument, "cannot delete devices: %v", err) } return deviceIds, nil } - deviceIds = getUniqueDeviceIds(request.DeviceIds) + deviceIds = getUniqueDeviceIds(request.GetDeviceIds()) if len(deviceIds) == 0 { return nil, status.Errorf(codes.InvalidArgument, "cannot delete devices: invalid DeviceIds") } @@ -112,7 +112,7 @@ func (s *Service) DeleteDevices(ctx context.Context, request *pb.DeleteDevicesRe return &pb.DeleteDevicesResponse{}, nil } - var deletedDeviceIDs []string + deletedDeviceIDs := make([]string, 0, len(deviceIDs)) for _, deviceID := range deviceIDs { ok, err := deleteDevice(tx, deviceID, owner) if err != nil { @@ -126,7 +126,9 @@ func (s *Service) DeleteDevices(ctx context.Context, request *pb.DeleteDevicesRe s.publishDevicesUnregistered(ctx, owner, userID, s.hubID, deletedDeviceIDs) - return &pb.DeleteDevicesResponse{ - DeviceIds: deletedDeviceIDs, - }, nil + resp := &pb.DeleteDevicesResponse{} + if len(deletedDeviceIDs) > 0 { + resp.DeviceIds = deletedDeviceIDs + } + return resp, nil } diff --git a/identity-store/service/deleteDevices_test.go b/identity-store/service/deleteDevices_test.go index 6ddddda66..1ee423c75 100644 --- a/identity-store/service/deleteDevices_test.go +++ b/identity-store/service/deleteDevices_test.go @@ -145,8 +145,8 @@ func TestServiceDeleteDevices(t *testing.T) { return } require.NoError(t, err) - sort.Strings(tt.want.DeviceIds) - sort.Strings(got.DeviceIds) + sort.Strings(tt.want.GetDeviceIds()) + sort.Strings(got.GetDeviceIds()) require.Equal(t, tt.want, got) }) } diff --git a/identity-store/service/getDevices_test.go b/identity-store/service/getDevices_test.go index 928fd73c5..1d1544012 100644 --- a/identity-store/service/getDevices_test.go +++ b/identity-store/service/getDevices_test.go @@ -9,7 +9,6 @@ import ( kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc" "github.com/plgd-dev/hub/v2/test" "github.com/plgd-dev/hub/v2/test/config" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" ) @@ -27,13 +26,13 @@ func TestUserDevicesList(t *testing.T) { }() persistDevice(t, s.service.persistence, newTestDevice()) err := s.service.GetDevices(newGetDevicesRequest(), srv) - assert.NoError(t, err) + require.NoError(t, err) r := map[string]*pb.Device{ testDeviceID: { DeviceId: testDeviceID, }, } - assert.Equal(t, r, srv.resourceValues) + require.Equal(t, r, srv.resourceValues) } func TestListingMoreDevices(t *testing.T) { @@ -53,8 +52,7 @@ func TestListingMoreDevices(t *testing.T) { persistDevice(t, s.service.persistence, d) err := s.service.GetDevices(newGetDevicesRequest(), srv) - assert := assert.New(t) - assert.NoError(err) + require.NoError(t, err) r := map[string]*pb.Device{ testDeviceID: { DeviceId: testDeviceID, @@ -63,7 +61,7 @@ func TestListingMoreDevices(t *testing.T) { DeviceId: d.DeviceID, }, } - assert.Equal(r, srv.resourceValues) + require.Equal(t, r, srv.resourceValues) } func newGetDevicesRequest() *pb.GetDevicesRequest { @@ -86,7 +84,7 @@ func (d *mockGeDevicesServer) Send(r *pb.Device) error { if d.resourceValues == nil { d.resourceValues = make(map[string]*pb.Device) } - d.resourceValues[r.DeviceId] = r + d.resourceValues[r.GetDeviceId()] = r return nil } diff --git a/identity-store/service/service_test.go b/identity-store/service/service_test.go index 78d96afff..fdd330898 100644 --- a/identity-store/service/service_test.go +++ b/identity-store/service/service_test.go @@ -15,7 +15,6 @@ import ( natsTest "github.com/plgd-dev/hub/v2/resource-aggregate/cqrs/eventbus/nats/test" "github.com/plgd-dev/hub/v2/test" "github.com/plgd-dev/hub/v2/test/config" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace/noop" ) @@ -113,5 +112,5 @@ func persistDevice(t *testing.T, p Persistence, d *persistence.AuthorizedDevice) tx := p.NewTransaction(context.Background()) defer tx.Close() err := tx.Persist(d) - assert.Nil(t, err) + require.NoError(t, err) } diff --git a/pkg/config/database/config.go b/pkg/config/database/config.go index c0eb846bb..f1ecaa699 100644 --- a/pkg/config/database/config.go +++ b/pkg/config/database/config.go @@ -1,6 +1,7 @@ package database import ( + "errors" "fmt" "reflect" "strings" @@ -31,7 +32,7 @@ func (c *Config[MongoConfig, CQLDBConfig]) Validate() error { switch c.Use.ToLower() { case MongoDB.ToLower(): if reflect.ValueOf(c.MongoDB).Kind() == reflect.Ptr && reflect.ValueOf(c.MongoDB).IsNil() { - return fmt.Errorf("mongoDB - is empty") + return errors.New("mongoDB - is empty") } if err := c.MongoDB.Validate(); err != nil { return fmt.Errorf("mongoDB.%w", err) @@ -39,7 +40,7 @@ func (c *Config[MongoConfig, CQLDBConfig]) Validate() error { c.Use = "mongoDB" case CqlDB.ToLower(): if reflect.ValueOf(c.CqlDB).Kind() == reflect.Ptr && reflect.ValueOf(c.CqlDB).IsNil() { - return fmt.Errorf("cqlDB - is empty") + return errors.New("cqlDB - is empty") } if err := c.CqlDB.Validate(); err != nil { return fmt.Errorf("cqlDB.%w", err) diff --git a/pkg/cqldb/cqldb.go b/pkg/cqldb/cqldb.go index 49af196da..b47ab61be 100644 --- a/pkg/cqldb/cqldb.go +++ b/pkg/cqldb/cqldb.go @@ -130,9 +130,9 @@ func New(ctx context.Context, cfg Config, tls *tls.Config, logger log.Logger, _ logger: logger, } - s.onClear = func(c context.Context) error { + s.onClear = func(clearCtx context.Context) error { // default clear function drops the whole database - return s.DropKeyspace(ctx) + return s.DropKeyspace(clearCtx) } return s, nil } diff --git a/pkg/fsnotify/fsnotify_test.go b/pkg/fsnotify/fsnotify_test.go index e2503805b..f5a9f703a 100644 --- a/pkg/fsnotify/fsnotify_test.go +++ b/pkg/fsnotify/fsnotify_test.go @@ -25,7 +25,7 @@ func TestWatcher(t *testing.T) { err = w.Add("/tmp") require.NoError(t, err) - onEventHandler := func(event Event) {} + onEventHandler := func(Event) {} w.AddOnEventHandler(&onEventHandler) w.RemoveOnEventHandler(&onEventHandler) diff --git a/pkg/log/log.go b/pkg/log/log.go index 40d0182cc..c4aaee370 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -293,7 +293,7 @@ var getLogFuncMap = map[zapcore.Level]func(l *WrapSuggarLogger) func(args ...int FatalLevel: func(l *WrapSuggarLogger) func(args ...interface{}) { return l.Fatal }, } -var emptyLogFunc = func(args ...interface{}) { +var emptyLogFunc = func(...interface{}) { // do nothing } diff --git a/pkg/log/logKeys.go b/pkg/log/logKeys.go index aa6335560..0ffe57c60 100644 --- a/pkg/log/logKeys.go +++ b/pkg/log/logKeys.go @@ -29,6 +29,7 @@ var ( MessageKey = "message" SubjectsKey = "subjects" CertManagerKey = "certManager" + LocalEndpointsKey = "localEndpoints" ) func DurationToMilliseconds(duration time.Duration) float32 { diff --git a/pkg/log/log_test.go b/pkg/log/log_test.go index ced4caf0d..0a453ef96 100644 --- a/pkg/log/log_test.go +++ b/pkg/log/log_test.go @@ -3,12 +3,12 @@ package log import ( "crypto/x509" "crypto/x509/pkix" - "fmt" + "errors" "testing" "time" pkgX509 "github.com/plgd-dev/hub/v2/pkg/security/x509" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestNew(t *testing.T) { @@ -17,34 +17,34 @@ func TestNew(t *testing.T) { config := MakeDefaultConfig() Setup(config) - assert.NotPanics(t, func() { Debug(testStr) }) - assert.NotPanics(t, func() { Info(testStr) }) - assert.NotPanics(t, func() { + require.NotPanics(t, func() { Debug(testStr) }) + require.NotPanics(t, func() { Info(testStr) }) + require.NotPanics(t, func() { Info(testStr, pkgX509.NewError([][]*x509.Certificate{{&x509.Certificate{ Subject: pkix.Name{ CommonName: "certName", }, - }}}, fmt.Errorf(" x509"))) + }}}, errors.New(" x509"))) }) - assert.NotPanics(t, func() { Warn(testStr) }) - assert.NotPanics(t, func() { Error(testStr) }) + require.NotPanics(t, func() { Warn(testStr) }) + require.NotPanics(t, func() { Error(testStr) }) - assert.NotPanics(t, func() { Debugf(testStr) }) - assert.NotPanics(t, func() { Infof(testStr) }) - assert.NotPanics(t, func() { Warnf(testStr) }) - assert.NotPanics(t, func() { Errorf(testStr) }) + require.NotPanics(t, func() { Debugf(testStr) }) + require.NotPanics(t, func() { Infof(testStr) }) + require.NotPanics(t, func() { Warnf(testStr) }) + require.NotPanics(t, func() { Errorf(testStr) }) timesStr := []string{"rfc3339nano", "rfc3339", "iso8601", "millis", "nanos", ""} for _, str := range timesStr { var v TimeEncoderWrapper - assert.NoError(t, v.UnmarshalText([]byte(str))) + require.NoError(t, v.UnmarshalText([]byte(str))) text, err := v.MarshalText() - assert.NoError(t, err) - assert.Equal(t, str, string(text)) + require.NoError(t, err) + require.Equal(t, str, string(text)) } - assert.Equal(t, float32(1000), DurationToMilliseconds(time.Second)) - assert.Error(t, LogAndReturnError(fmt.Errorf(testStr))) + require.InEpsilon(t, float32(1000), DurationToMilliseconds(time.Second), 0.1) + require.Error(t, LogAndReturnError(errors.New(testStr))) cfg := MakeDefaultConfig() - assert.NoError(t, cfg.Validate()) + require.NoError(t, cfg.Validate()) } diff --git a/pkg/net/coap/getResourceLinks.go b/pkg/net/coap/getResourceLinks.go new file mode 100644 index 000000000..770a8bb63 --- /dev/null +++ b/pkg/net/coap/getResourceLinks.go @@ -0,0 +1,85 @@ +package coap + +import ( + "context" + "errors" + "fmt" + "net" + + "github.com/plgd-dev/device/v2/schema" + "github.com/plgd-dev/device/v2/schema/device" + "github.com/plgd-dev/device/v2/schema/interfaces" + "github.com/plgd-dev/device/v2/schema/resources" + "github.com/plgd-dev/go-coap/v3/message" + "github.com/plgd-dev/go-coap/v3/message/codes" + "github.com/plgd-dev/go-coap/v3/message/pool" + "github.com/plgd-dev/hub/v2/coap-gateway/uri" + "github.com/plgd-dev/kit/v2/codec/cbor" +) + +type ClientConn = interface { + Get(ctx context.Context, path string, opts ...message.Option) (*pool.Message, error) + ReleaseMessage(m *pool.Message) + RemoteAddr() net.Addr +} + +// GetResourceLinks queries the resource links from the given resource. +func GetResourceLinks(ctx context.Context, coapConn ClientConn, href string, opts ...message.Option) (schema.ResourceLinks, uint64, error) { + msg, err := coapConn.Get(ctx, href, opts...) + if err != nil { + return schema.ResourceLinks{}, 0, err + } + defer coapConn.ReleaseMessage(msg) + + if msg.Code() != codes.Content { + return schema.ResourceLinks{}, 0, fmt.Errorf("invalid response code %v", msg.Code()) + } + + data := msg.Body() + if data == nil { + return schema.ResourceLinks{}, 0, errors.New("empty response") + } + + var links schema.ResourceLinks + err = cbor.ReadFrom(msg.Body(), &links) + if err != nil { + return schema.ResourceLinks{}, 0, err + } + + return links, msg.Sequence(), nil +} + +// GetResourceLinksWithLinkInterface query resource links from the given resource with the interface oic.if.ll. +func GetResourceLinksWithLinkInterface(ctx context.Context, coapConn ClientConn, href string) (schema.ResourceLinks, uint64, error) { + return GetResourceLinks(ctx, coapConn, href, message.Option{ + ID: message.URIQuery, + Value: []byte(uri.InterfaceQueryKeyPrefix + interfaces.OC_IF_LL), + }) +} + +// GetEndpointsFromResourceType retrieves the endpoints associated with a specific resource type. +func GetEndpointsFromResourceType(ctx context.Context, coapConn ClientConn, resourceType string) ([]string, error) { + links, _, err := GetResourceLinks(ctx, coapConn, resources.ResourceURI, message.Option{ + ID: message.URIQuery, + Value: []byte(uri.InterfaceQueryKeyPrefix + interfaces.OC_IF_LL), + }, message.Option{ + ID: message.URIQuery, + Value: []byte(uri.ResourceTypeQueryKeyPrefix + resourceType), + }) + if err != nil { + return nil, err + } + if len(links) == 0 { + return nil, errors.New("no local endpoints found") + } + endpoints := make([]string, 0, 8) + for _, ep := range links[0].Endpoints { + endpoints = append(endpoints, ep.URI) + } + return endpoints, nil +} + +// GetEndpointsFromDeviceResource retrieves the endpoints from the device resource. +func GetEndpointsFromDeviceResource(ctx context.Context, coapConn ClientConn) ([]string, error) { + return GetEndpointsFromResourceType(ctx, coapConn, device.ResourceType) +} diff --git a/pkg/net/coap/getResourceLinks_test.go b/pkg/net/coap/getResourceLinks_test.go new file mode 100644 index 000000000..9b951b49a --- /dev/null +++ b/pkg/net/coap/getResourceLinks_test.go @@ -0,0 +1,244 @@ +package coap_test + +import ( + "bytes" + "context" + "net" + "strings" + "testing" + + "github.com/plgd-dev/device/v2/schema" + "github.com/plgd-dev/device/v2/schema/device" + "github.com/plgd-dev/device/v2/schema/resources" + "github.com/plgd-dev/go-coap/v3/message" + "github.com/plgd-dev/go-coap/v3/message/codes" + "github.com/plgd-dev/go-coap/v3/message/pool" + "github.com/plgd-dev/hub/v2/coap-gateway/uri" + "github.com/plgd-dev/hub/v2/pkg/net/coap" + "github.com/plgd-dev/hub/v2/test" + "github.com/stretchr/testify/require" +) + +type testCoapConn struct { + devID string + links schema.ResourceLinks + t *testing.T +} + +func (t *testCoapConn) Get(ctx context.Context, path string, opts ...message.Option) (*pool.Message, error) { + var rtFilter []string + for _, opt := range opts { + if opt.ID == message.URIQuery { + vals := strings.SplitN(string(opt.Value), "=", 2) + if len(vals) != 2 { + continue + } + if vals[0] == uri.ResourceTypeQueryKey { + rtFilter = append(rtFilter, vals[1]) + } + } + } + resp := pool.NewMessage(ctx) + switch path { + case device.ResourceURI: + resp.SetCode(codes.Content) + resp.SetContentFormat(message.AppOcfCbor) + resp.SetBody(bytes.NewReader(test.EncodeToCbor(t.t, device.Device{ + ID: t.devID, + }))) + return resp, nil + case resources.ResourceURI: + links := t.links + if len(rtFilter) > 0 { + links = links.GetResourceLinks(rtFilter...) + } + if len(links) == 0 { + resp.SetCode(codes.BadRequest) + return resp, nil + } + resp.SetCode(codes.Content) + resp.SetContentFormat(message.AppOcfCbor) + resp.SetBody(bytes.NewReader(test.EncodeToCbor(t.t, links))) + return resp, nil + } + resp.SetCode(codes.NotFound) + return resp, nil +} + +func (t *testCoapConn) ReleaseMessage(*pool.Message) { +} + +func (t *testCoapConn) RemoteAddr() net.Addr { + return &net.TCPAddr{} +} + +func TestGetEndpointsFromDeviceResource(t *testing.T) { + type args struct { + ctx context.Context + coapConn coap.ClientConn + } + tests := []struct { + name string + args args + want []string + wantErr bool + }{ + { + name: "valid", + args: args{ + ctx: context.Background(), + coapConn: &testCoapConn{ + t: t, + devID: "dev1", + links: schema.ResourceLinks{ + { + DeviceID: "00000000-0000-0000-0000-000000000001", + Href: device.ResourceURI, + ResourceTypes: []string{device.ResourceType}, + Endpoints: []schema.Endpoint{ + { + URI: "coap://localhost:5683", + }, + { + URI: "coaps://localhost:5684", + }, + }, + }, + }, + }, + }, + want: []string{"coap://localhost:5683", "coaps://localhost:5684"}, + }, + { + name: "rt not found", + args: args{ + ctx: context.Background(), + coapConn: &testCoapConn{ + t: t, + devID: "dev1", + links: schema.ResourceLinks{ + { + DeviceID: "00000000-0000-0000-0000-000000000001", + Href: resources.ResourceURI, + ResourceTypes: []string{resources.ResourceType}, + Endpoints: []schema.Endpoint{ + { + URI: "coap://localhost:5683", + }, + { + URI: "coaps://localhost:5684", + }, + }, + }, + }, + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := coap.GetEndpointsFromDeviceResource(tt.args.ctx, tt.args.coapConn) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} + +func TestGetResourceLinksWithLinkInterface(t *testing.T) { + type args struct { + ctx context.Context + coapConn coap.ClientConn + href string + } + tests := []struct { + name string + args args + want schema.ResourceLinks + wantErr bool + }{ + { + name: "valid", + args: args{ + ctx: context.Background(), + href: resources.ResourceURI, + coapConn: &testCoapConn{ + t: t, + devID: "dev1", + links: schema.ResourceLinks{ + { + DeviceID: "00000000-0000-0000-0000-000000000001", + Href: device.ResourceURI, + ResourceTypes: []string{device.ResourceType}, + Endpoints: []schema.Endpoint{ + { + URI: "coap://localhost:5683", + }, + { + URI: "coaps://localhost:5684", + }, + }, + }, + }, + }, + }, + want: schema.ResourceLinks{ + { + DeviceID: "00000000-0000-0000-0000-000000000001", + Href: device.ResourceURI, + ResourceTypes: []string{device.ResourceType}, + Endpoints: []schema.Endpoint{ + { + URI: "coap://localhost:5683", + }, + { + URI: "coaps://localhost:5684", + }, + }, + }, + }, + }, + { + name: "rt not found", + args: args{ + ctx: context.Background(), + href: device.ResourceURI, + coapConn: &testCoapConn{ + t: t, + devID: "dev1", + links: schema.ResourceLinks{ + { + DeviceID: "00000000-0000-0000-0000-000000000001", + Href: resources.ResourceURI, + ResourceTypes: []string{resources.ResourceType}, + Endpoints: []schema.Endpoint{ + { + URI: "coap://localhost:5683", + }, + { + URI: "coaps://localhost:5684", + }, + }, + }, + }, + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, _, err := coap.GetResourceLinksWithLinkInterface(tt.args.ctx, tt.args.coapConn, tt.args.href) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/net/coap/service/config.go b/pkg/net/coap/service/config.go index 59eeee3ac..eeae3dfd4 100644 --- a/pkg/net/coap/service/config.go +++ b/pkg/net/coap/service/config.go @@ -1,6 +1,7 @@ package service import ( + "errors" "fmt" "strings" "time" @@ -48,7 +49,7 @@ func (c *Config) validateKeepAliveAndInactivityMonitor() error { } } if c.KeepAlive == nil && c.InactivityMonitor == nil { - return fmt.Errorf("keepAlive or inactivityMonitor must be set") + return errors.New("keepAlive or inactivityMonitor must be set") } return nil } diff --git a/pkg/net/coap/service/service_test.go b/pkg/net/coap/service/service_test.go index 5cfdafbb2..93d560629 100644 --- a/pkg/net/coap/service/service_test.go +++ b/pkg/net/coap/service/service_test.go @@ -16,6 +16,7 @@ import ( "github.com/plgd-dev/hub/v2/pkg/log" "github.com/plgd-dev/hub/v2/pkg/service" "github.com/plgd-dev/hub/v2/test/config" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/atomic" ) @@ -60,8 +61,8 @@ func TestNew(t *testing.T) { }, options: []func(*Options){ WithMessagePool(pool.New(uint32(1024), 1024)), - WithOnNewConnection(func(conn mux.Conn) {}), - WithOnInactivityConnection(func(conn mux.Conn) {}), + WithOnNewConnection(func(mux.Conn) {}), + WithOnInactivityConnection(func(mux.Conn) {}), WithOverrideTLS(func(cfg *tls.Config) *tls.Config { return cfg }), }, }, @@ -87,8 +88,8 @@ func TestNew(t *testing.T) { }, options: []func(*Options){ WithMessagePool(pool.New(uint32(1024), 1024)), - WithOnNewConnection(func(conn mux.Conn) {}), - WithOnInactivityConnection(func(conn mux.Conn) {}), + WithOnNewConnection(func(mux.Conn) {}), + WithOnInactivityConnection(func(mux.Conn) {}), WithOverrideTLS(func(cfg *tls.Config) *tls.Config { return cfg }), }, }, @@ -107,8 +108,8 @@ func TestNew(t *testing.T) { } require.NoError(t, err) go func() { - err := got.Serve() - require.NoError(t, err) + errS := got.Serve() + assert.NoError(t, errS) }() err = got.Close() require.NoError(t, err) @@ -152,8 +153,8 @@ func TestOnClientInactivityTCP(t *testing.T) { })) require.NoError(t, err) go func() { - err := got.Serve() - require.NoError(t, err) + errS := got.Serve() + assert.NoError(t, errS) }() time.Sleep(time.Second * 3) @@ -217,8 +218,8 @@ func TestOnClientInactivityUDP(t *testing.T) { })) require.NoError(t, err) go func() { - err := got.Serve() - require.NoError(t, err) + errS := got.Serve() + assert.NoError(t, errS) }() time.Sleep(time.Second * 3) @@ -278,8 +279,8 @@ func TestOnClientInactivityCustomTCP(t *testing.T) { closeChan := make(chan struct{}, 2) got, err := New(ctx, cfg, router, fileWatcher, logger, WithOnInactivityConnection(func(conn mux.Conn) { numInactiveClients.Inc() - err := conn.Close() - require.NoError(t, err) + errC := conn.Close() + require.NoError(t, errC) }), WithOnNewConnection(func(conn mux.Conn) { conn.AddOnClose(func() { closeChan <- struct{}{} @@ -287,8 +288,8 @@ func TestOnClientInactivityCustomTCP(t *testing.T) { })) require.NoError(t, err) go func() { - err := got.Serve() - require.NoError(t, err) + errS := got.Serve() + assert.NoError(t, errS) }() time.Sleep(time.Second * 3) @@ -349,8 +350,8 @@ func TestOnClientInactivityCustomUDP(t *testing.T) { closeChan := make(chan struct{}, 2) got, err := New(ctx, cfg, router, fileWatcher, logger, WithOnInactivityConnection(func(conn mux.Conn) { numInactiveClients.Inc() - err := conn.Close() - require.NoError(t, err) + errC := conn.Close() + require.NoError(t, errC) }), WithOnNewConnection(func(conn mux.Conn) { conn.AddOnClose(func() { closeChan <- struct{}{} @@ -358,8 +359,8 @@ func TestOnClientInactivityCustomUDP(t *testing.T) { })) require.NoError(t, err) go func() { - err := got.Serve() - require.NoError(t, err) + errS := got.Serve() + assert.NoError(t, errS) }() time.Sleep(time.Second * 3) diff --git a/pkg/net/grpc/error_test.go b/pkg/net/grpc/error_test.go index 50cbfc77c..8366fd3c1 100644 --- a/pkg/net/grpc/error_test.go +++ b/pkg/net/grpc/error_test.go @@ -97,7 +97,7 @@ func TestForwardErrorf(t *testing.T) { s, ok := status.FromError(err) require.True(t, ok) assert.Equal(t, tt.wantCode, s.Code()) - test.CheckProtobufs(t, tt.wantDetails, s.Details(), test.AssertToCheckFunc(assert.Equal)) + test.CheckProtobufs(t, tt.wantDetails, s.Details(), test.RequireToCheckFunc(require.Equal)) assert.Equal(t, tt.wantMessage, s.Message()) }) } diff --git a/pkg/net/grpc/server/makeDefaultOptions.go b/pkg/net/grpc/server/makeDefaultOptions.go index 667b94934..868ac95d2 100644 --- a/pkg/net/grpc/server/makeDefaultOptions.go +++ b/pkg/net/grpc/server/makeDefaultOptions.go @@ -251,7 +251,7 @@ func MakeDefaultOptions(auth pkgGrpc.AuthInterceptors, logger log.Logger, tracer }, } unaryInterceptors := []grpc.UnaryServerInterceptor{ - func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { setGrpcRequest(ctx, req) return handler(ctx, req) }, @@ -298,7 +298,7 @@ func WithWhiteListedMethods(method ...string) Option { } func NewAuth(validator pkgGrpc.Validator, opts ...Option) pkgGrpc.AuthInterceptors { - interceptor := pkgGrpc.ValidateJWTWithValidator(validator, func(ctx context.Context, method string) jwt.ClaimsValidator { + interceptor := pkgGrpc.ValidateJWTWithValidator(validator, func(context.Context, string) jwt.ClaimsValidator { return pkgJwt.NewScopeClaims() }) var cfg config diff --git a/pkg/net/grpc/stub.pb_test.go b/pkg/net/grpc/stub.pb_test.go index 093359148..01c8ddcc3 100644 --- a/pkg/net/grpc/stub.pb_test.go +++ b/pkg/net/grpc/stub.pb_test.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: github.com/plgd-dev/hub/pkg/net/grpc/stub.proto package grpc_test diff --git a/pkg/net/grpc/stub_grpc.pb_test.go b/pkg/net/grpc/stub_grpc.pb_test.go index 923971e19..4092c7941 100644 --- a/pkg/net/grpc/stub_grpc.pb_test.go +++ b/pkg/net/grpc/stub_grpc.pb_test.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc v5.26.1 // source: github.com/plgd-dev/hub/pkg/net/grpc/stub.proto package grpc_test diff --git a/pkg/net/grpc/stub_test.go b/pkg/net/grpc/stub_test.go index 039d4f60c..ea2575ff2 100644 --- a/pkg/net/grpc/stub_test.go +++ b/pkg/net/grpc/stub_test.go @@ -17,7 +17,7 @@ func StubGrpcServer(opts ...grpc.ServerOption) *server.Server { } func StubGrpcClient(addr string) StubServiceClient { - conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { panic(err) } diff --git a/pkg/net/http/convertError_test.go b/pkg/net/http/convertError_test.go index b1194c801..10c6a9fea 100644 --- a/pkg/net/http/convertError_test.go +++ b/pkg/net/http/convertError_test.go @@ -2,6 +2,7 @@ package http import ( "context" + "errors" "fmt" "net/http" "testing" @@ -42,11 +43,11 @@ func TestErrToStatus(t *testing.T) { { name: "coap", args: args{ - err: coapStatus.Error(forbidden, fmt.Errorf("coap error")), + err: coapStatus.Error(forbidden, errors.New("coap error")), }, want: http.StatusForbidden, }, - {name: "grpc", args: args{err: fmt.Errorf("unknown error")}, want: http.StatusInternalServerError}, + {name: "grpc", args: args{err: errors.New("unknown error")}, want: http.StatusInternalServerError}, {name: "sdkError", args: args{err: SdkError{errorCode: codes.PermissionDenied}}, want: http.StatusForbidden}, } for _, tt := range tests { diff --git a/pkg/net/http/interceptor.go b/pkg/net/http/interceptor.go index 37125b0b5..41b27d629 100644 --- a/pkg/net/http/interceptor.go +++ b/pkg/net/http/interceptor.go @@ -46,7 +46,7 @@ func (c DeniedClaims) Validate() error { } func MakeClaimsFunc(methods map[string][]AuthArgs) ClaimsFunc { - return func(ctx context.Context, method, uri string) jwt.ClaimsValidator { + return func(_ context.Context, method, uri string) jwt.ClaimsValidator { args, ok := methods[method] if !ok { return &DeniedClaims{Err: fmt.Errorf("inaccessible method: %v", method)} diff --git a/pkg/net/http/loggingMiddleware.go b/pkg/net/http/loggingMiddleware.go index a6a5761ef..19c592514 100644 --- a/pkg/net/http/loggingMiddleware.go +++ b/pkg/net/http/loggingMiddleware.go @@ -2,6 +2,7 @@ package http import ( "bufio" + "errors" "fmt" "net" "net/http" @@ -58,7 +59,7 @@ func (w *statusWriter) Write(b []byte) (int, error) { func (w *statusWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { writer, ok := w.ResponseWriter.(http.Hijacker) if !ok { - return nil, nil, fmt.Errorf("not supported by the underlying writer") + return nil, nil, errors.New("not supported by the underlying writer") } return writer.Hijack() } @@ -70,7 +71,7 @@ func (w *statusWriter) Flush() { } } -var toNil = func(args ...interface{}) { +var toNil = func(...interface{}) { // Do nothing because we don't want to log anything } diff --git a/pkg/net/http/service/config.go b/pkg/net/http/service/config.go index 76af609f4..cdde59691 100644 --- a/pkg/net/http/service/config.go +++ b/pkg/net/http/service/config.go @@ -1,6 +1,7 @@ package http import ( + "errors" "fmt" "github.com/plgd-dev/hub/v2/pkg/config" @@ -32,19 +33,19 @@ func (c *Config) Validate() error { return fmt.Errorf("HTTPConnection.%w", err) } if c.TraceProvider == nil { - return fmt.Errorf("traceProvider is required") + return errors.New("traceProvider is required") } if c.AuthRules == nil { - return fmt.Errorf("authRules is required") + return errors.New("authRules is required") } if c.FileWatcher == nil { - return fmt.Errorf("fileWatcher is required") + return errors.New("fileWatcher is required") } if c.Logger == nil { - return fmt.Errorf("logger is required") + return errors.New("logger is required") } if c.ServiceName == "" { - return fmt.Errorf("serviceName is required") + return errors.New("serviceName is required") } return nil diff --git a/pkg/opentelemetry/otelcoap/opentelemetry.go b/pkg/opentelemetry/otelcoap/opentelemetry.go index 6057bf73f..cbe67c104 100644 --- a/pkg/opentelemetry/otelcoap/opentelemetry.go +++ b/pkg/opentelemetry/otelcoap/opentelemetry.go @@ -109,5 +109,5 @@ func Start(ctx context.Context, path, method string, opts ...Option) (context.Co spanOpts = append(spanOpts, cfg.SpanStartOptions...) } - return tracer.Start(ctx, DefaultTransportFormatter(path), spanOpts...) + return tracer.Start(ctx, DefaultTransportFormatter(path), spanOpts...) //nolint:spancheck } diff --git a/pkg/security/certManager/client/certManager.go b/pkg/security/certManager/client/certManager.go index 8e550ee30..2ca175623 100644 --- a/pkg/security/certManager/client/certManager.go +++ b/pkg/security/certManager/client/certManager.go @@ -2,6 +2,7 @@ package client import ( "crypto/tls" + "errors" "fmt" "github.com/plgd-dev/hub/v2/pkg/config/property/urischeme" @@ -42,7 +43,7 @@ func (c *Config) Validate() error { func (c *Config) CAPoolArray() ([]urischeme.URIScheme, error) { if !c.validated { - return nil, fmt.Errorf("call Validate() first") + return nil, errors.New("call Validate() first") } return c.caPoolArray, nil } diff --git a/pkg/security/certManager/general/certManager.go b/pkg/security/certManager/general/certManager.go index b249ffab4..637e63358 100644 --- a/pkg/security/certManager/general/certManager.go +++ b/pkg/security/certManager/general/certManager.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "crypto/tls" "crypto/x509" + "errors" "fmt" "strings" "sync" @@ -191,7 +192,7 @@ func (a *CertManager) getTLSKeyPair() (*tls.Certificate, error) { } } if a.private.tlsKeyPair == nil { - return nil, fmt.Errorf("certificate is not loaded") + return nil, errors.New("certificate is not loaded") } return a.private.tlsKeyPair, nil diff --git a/pkg/security/certManager/general/certManager_test.go b/pkg/security/certManager/general/certManager_test.go index 433501cbd..3101e880b 100644 --- a/pkg/security/certManager/general/certManager_test.go +++ b/pkg/security/certManager/general/certManager_test.go @@ -178,18 +178,18 @@ func TestCertManagerWithExpiredCA(t *testing.T) { defer mng.Close() pool := mng.GetCertificateAuthorities() require.NotNil(t, pool) - require.Equal(t, 1, len(pool.Subjects())) //nolint:staticcheck + require.Len(t, pool.Subjects(), 1) //nolint:staticcheck time.Sleep(time.Second * 2) pool = mng.GetCertificateAuthorities() require.NotNil(t, pool) - require.Equal(t, 0, len(pool.Subjects())) //nolint:staticcheck + require.Empty(t, pool.Subjects()) //nolint:staticcheck caPem, _ = getCA(t, time.Now(), time.Second*100) err = os.WriteFile(caFile.Name(), caPem, os.FileMode(os.O_RDWR)) require.NoError(t, err) time.Sleep(time.Second * 1) pool = mng.GetCertificateAuthorities() require.NotNil(t, pool) - require.Equal(t, 1, len(pool.Subjects())) //nolint:staticcheck + require.Len(t, pool.Subjects(), 1) //nolint:staticcheck } // Check when cert expires diff --git a/pkg/security/certManager/server/certManager.go b/pkg/security/certManager/server/certManager.go index dd3a3fbb6..953d35cbb 100644 --- a/pkg/security/certManager/server/certManager.go +++ b/pkg/security/certManager/server/certManager.go @@ -2,6 +2,7 @@ package server import ( "crypto/tls" + "errors" "fmt" "github.com/plgd-dev/hub/v2/pkg/config/property/urischeme" @@ -43,7 +44,7 @@ func (c *Config) Validate() error { func (c *Config) CAPoolArray() ([]urischeme.URIScheme, error) { if !c.validated { - return nil, fmt.Errorf("call Validate() first") + return nil, errors.New("call Validate() first") } return c.caPoolArray, nil } diff --git a/pkg/security/certificateSigner/certificateSigner.go b/pkg/security/certificateSigner/certificateSigner.go index 2620e5e83..707588448 100644 --- a/pkg/security/certificateSigner/certificateSigner.go +++ b/pkg/security/certificateSigner/certificateSigner.go @@ -6,7 +6,7 @@ import ( "crypto/rand" "crypto/x509" "encoding/pem" - "fmt" + "errors" "math/big" "time" @@ -58,11 +58,11 @@ func New(caCert []*x509.Certificate, caKey crypto.PrivateKey, opts ...Opt) *Cert func (s *CertificateSigner) Sign(_ context.Context, csr []byte) ([]byte, error) { if len(s.caCert) == 0 { - return nil, fmt.Errorf("cannot sign with empty signer CA certificates") + return nil, errors.New("cannot sign with empty signer CA certificates") } csrBlock, _ := pem.Decode(csr) if csrBlock == nil { - return nil, fmt.Errorf("pem not found") + return nil, errors.New("pem not found") } certificateRequest, err := x509.ParseCertificateRequest(csrBlock.Bytes) @@ -106,7 +106,7 @@ func (s *CertificateSigner) Sign(_ context.Context, csr []byte) ([]byte, error) ExtraExtensions: certificateRequest.Extensions, } if s.cfg.OverrideCertTemplate != nil { - if err := s.cfg.OverrideCertTemplate(&template); err != nil { + if err = s.cfg.OverrideCertTemplate(&template); err != nil { return nil, err } } diff --git a/pkg/security/jwt/claims_test.go b/pkg/security/jwt/claims_test.go index db045c83a..17398991a 100644 --- a/pkg/security/jwt/claims_test.go +++ b/pkg/security/jwt/claims_test.go @@ -132,7 +132,7 @@ func TestAudienceOfOne(t *testing.T) { c[pkgJwt.ClaimAudience] = "test" aud, err := c.GetAudience() require.NoError(t, err) - require.Equal(t, []string(aud), []string{c[pkgJwt.ClaimAudience].(string)}) + require.Equal(t, []string{c[pkgJwt.ClaimAudience].(string)}, []string(aud)) } func TestAudienceOfTwo(t *testing.T) { @@ -467,7 +467,7 @@ func TestParseToken(t *testing.T) { func checkClaims(t *testing.T, tokenClaims jwt.Claims, expError error) { token := config.CreateJwtToken(t, tokenClaims) - _, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) { + _, err := jwt.Parse(token, func(*jwt.Token) (interface{}, error) { return jwt.VerificationKeySet{ Keys: []jwt.VerificationKey{ []uint8(config.JWTSecret), @@ -482,7 +482,6 @@ func checkClaims(t *testing.T, tokenClaims jwt.Claims, expError error) { } func TestValidate(t *testing.T) { - now := time.Now() expiredTime := now.Add(-time.Hour) futureTime := now.Add(time.Hour) diff --git a/pkg/security/jwt/jwk.go b/pkg/security/jwt/jwk.go index d7a87eb16..054c6a390 100644 --- a/pkg/security/jwt/jwk.go +++ b/pkg/security/jwt/jwk.go @@ -2,6 +2,7 @@ package jwt import ( "context" + "errors" "fmt" "net/http" "sync" @@ -53,21 +54,21 @@ func (c *KeyCache) GetKey(token *jwt.Token) (interface{}, error) { func (c *KeyCache) LookupKey(token *jwt.Token) (jwk.Key, error) { id, ok := token.Header["kid"].(string) if !ok { - return nil, fmt.Errorf("missing key id in token") + return nil, errors.New("missing key id in token") } c.m.Lock() defer c.m.Unlock() if c.keys == nil { - return nil, fmt.Errorf("empty JWK cache") + return nil, errors.New("empty JWK cache") } if key, ok := c.keys.LookupKeyID(id); ok { if key.Algorithm().String() == token.Method.Alg() { return key, nil } } - return nil, fmt.Errorf("could not find JWK") + return nil, errors.New("could not find JWK") } func (c *KeyCache) FetchKeys() error { diff --git a/pkg/security/jwt/scopeClaims_test.go b/pkg/security/jwt/scopeClaims_test.go index 2912cc08d..f41adef4d 100644 --- a/pkg/security/jwt/scopeClaims_test.go +++ b/pkg/security/jwt/scopeClaims_test.go @@ -61,7 +61,7 @@ func TestScopeClaimsInvalidScope(t *testing.T) { func checkScopedClaims(t *testing.T, tokenClaims jwt.Claims, expError error) { token := config.CreateJwtToken(t, tokenClaims) - _, err := jwt.ParseWithClaims(token, &pkgJwt.ScopeClaims{}, func(t *jwt.Token) (interface{}, error) { + _, err := jwt.ParseWithClaims(token, &pkgJwt.ScopeClaims{}, func(*jwt.Token) (interface{}, error) { return jwt.VerificationKeySet{ Keys: []jwt.VerificationKey{ []uint8(config.JWTSecret), diff --git a/pkg/security/jwt/validator_test.go b/pkg/security/jwt/validator_test.go index 59ca74c91..baef741e4 100644 --- a/pkg/security/jwt/validator_test.go +++ b/pkg/security/jwt/validator_test.go @@ -67,36 +67,36 @@ func TestClaims(t *testing.T) { require.ErrorIs(t, err, jwt.ErrTokenExpired) clientID, err := c.GetClientID() - assert.NoError(t, err) - assert.Equal(t, "test.client.id", clientID) + require.NoError(t, err) + require.Equal(t, "test.client.id", clientID) email, err := c.GetEmail() - assert.NoError(t, err) - assert.Equal(t, "user@example.com", email) + require.NoError(t, err) + require.Equal(t, "user@example.com", email) scope, err := c.GetScope() - assert.Contains(t, scope, "test.scope") - assert.NoError(t, err) + require.Contains(t, scope, "test.scope") + require.NoError(t, err) audience, err := c.GetAudience() - assert.NoError(t, err) - assert.Contains(t, audience, "http://identity-server:3001/resources") - assert.Contains(t, audience, "test.resource") + require.NoError(t, err) + require.Contains(t, audience, "http://identity-server:3001/resources") + require.Contains(t, audience, "test.resource") exp, err := c.GetExpirationTime() - assert.NoError(t, err) - assert.Equal(t, 2019, exp.Year()) + require.NoError(t, err) + require.Equal(t, 2019, exp.Year()) id, err := c.GetID() - assert.NoError(t, err) - assert.Empty(t, id) + require.NoError(t, err) + require.Empty(t, id) iat, err := c.GetIssuedAt() - assert.NoError(t, err) - assert.Nil(t, iat) + require.NoError(t, err) + require.Nil(t, iat) iss, err := c.GetIssuer() - assert.NoError(t, err) - assert.Equal(t, iss, "http://identity-server:3001") + require.NoError(t, err) + require.Equal(t, "http://identity-server:3001", iss) nbf, err := c.GetNotBefore() - assert.NoError(t, err) - assert.Equal(t, 2019, nbf.Year()) + require.NoError(t, err) + require.Equal(t, 2019, nbf.Year()) sub, err := c.GetSubject() - assert.NoError(t, err) - assert.Equal(t, "1b87effa-34e2-4a44-82c6-6e0ab80209ff", sub) + require.NoError(t, err) + require.Equal(t, "1b87effa-34e2-4a44-82c6-6e0ab80209ff", sub) } func TestParser(t *testing.T) { diff --git a/pkg/security/oauth2/plgd_clientCrendetials.go b/pkg/security/oauth2/plgd_clientCrendetials.go index 2df542aa2..5a18a7df3 100644 --- a/pkg/security/oauth2/plgd_clientCrendetials.go +++ b/pkg/security/oauth2/plgd_clientCrendetials.go @@ -42,9 +42,9 @@ func (p *ClientCredentialsPlgdProvider) Exchange(ctx context.Context, authorizat m := pkgJwt.Claims(claims) c := p.Config.ToDefaultClientCredentials() if p.deviceIDClaim != "" { - deviceID, err := m.GetDeviceID(p.deviceIDClaim) - if err != nil { - return nil, fmt.Errorf("cannot get deviceIDClaim: %w", err) + deviceID, errG := m.GetDeviceID(p.deviceIDClaim) + if errG != nil { + return nil, fmt.Errorf("cannot get deviceIDClaim: %w", errG) } if deviceID == "" { return nil, fmt.Errorf("deviceIDClaim('%v') is not set in token", p.deviceIDClaim) diff --git a/pkg/security/x509/load.go b/pkg/security/x509/load.go index bd5bf03bd..c76dc905c 100644 --- a/pkg/security/x509/load.go +++ b/pkg/security/x509/load.go @@ -5,7 +5,6 @@ import ( "crypto/x509" "encoding/pem" "errors" - "fmt" "os" ) @@ -25,7 +24,7 @@ func ParseX509(pemBlock []byte) ([]*x509.Certificate, error) { for { certDERBlock, tmp := pem.Decode(data) if certDERBlock == nil { - return nil, fmt.Errorf("cannot decode pem block") + return nil, errors.New("cannot decode pem block") } certs, err := x509.ParseCertificates(certDERBlock.Bytes) if err != nil { @@ -44,7 +43,7 @@ func ParseX509(pemBlock []byte) ([]*x509.Certificate, error) { func ParsePrivateKey(pemBlock []byte) (*ecdsa.PrivateKey, error) { certDERBlock, _ := pem.Decode(pemBlock) if certDERBlock == nil { - return nil, fmt.Errorf("cannot decode pem block") + return nil, errors.New("cannot decode pem block") } if key, err := x509.ParsePKCS8PrivateKey(certDERBlock.Bytes); err == nil { diff --git a/pkg/security/x509/verify.go b/pkg/security/x509/verify.go index c1aaf0f29..218866e8d 100644 --- a/pkg/security/x509/verify.go +++ b/pkg/security/x509/verify.go @@ -3,7 +3,7 @@ package x509 import ( "bytes" "crypto/x509" - "fmt" + "errors" ) func IsRootCA(cert *x509.Certificate) bool { @@ -29,10 +29,10 @@ func setCAPools(roots *x509.CertPool, intermediates *x509.CertPool, certs []*x50 // Verify verifies certificate against certificate authorities. func Verify(certificates []*x509.Certificate, certificateAuthorities []*x509.Certificate, useSystemRoots bool, opts x509.VerifyOptions) ([][]*x509.Certificate, error) { if len(certificates) == 0 { - return nil, fmt.Errorf("at least one certificate need to be set") + return nil, errors.New("at least one certificate need to be set") } if len(certificateAuthorities) == 0 { - return nil, fmt.Errorf("at least one certificate authority need to be set") + return nil, errors.New("at least one certificate authority need to be set") } intermediateCA := x509.NewCertPool() rootCA := x509.NewCertPool() diff --git a/pkg/service/service.go b/pkg/service/service.go index cb9f5c17c..3d58cbb64 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -1,7 +1,7 @@ package service import ( - "fmt" + "errors" "os" "os/signal" "sync" @@ -40,7 +40,7 @@ func (s *Service) Add(services ...APIService) { func (s *Service) Serve() error { if !s.serving.CompareAndSwap(false, true) { - return fmt.Errorf("already serving") + return errors.New("already serving") } defer close(s.done) var wg sync.WaitGroup diff --git a/pkg/strings/slice_test.go b/pkg/strings/slice_test.go index cc5ce265f..6fee31e9f 100644 --- a/pkg/strings/slice_test.go +++ b/pkg/strings/slice_test.go @@ -65,7 +65,7 @@ func TestIntersection(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := Intersection(tt.args.s1, tt.args.s2) - require.Equal(t, got, tt.want) + require.Equal(t, tt.want, got) }) } } @@ -121,8 +121,8 @@ func TestSplit(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gotTrue, gotFalse := Split(tt.args.s, tt.args.f) - require.Equal(t, gotTrue, tt.wantTrue) - require.Equal(t, gotFalse, tt.wantFalse) + require.Equal(t, tt.wantTrue, gotTrue) + require.Equal(t, tt.wantFalse, gotFalse) }) } } @@ -168,7 +168,7 @@ func TestUnique(t *testing.T) { got := Unique(tt.args.s) sort.Strings(got) sort.Strings(tt.want) - require.Equal(t, got, tt.want) + require.Equal(t, tt.want, got) }) } } @@ -211,7 +211,7 @@ func TestContains(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := Contains(tt.args.slice, tt.args.s) - require.Equal(t, got, tt.want) + require.Equal(t, tt.want, got) }) } } diff --git a/pkg/strings/sortedSlice_test.go b/pkg/strings/sortedSlice_test.go index b7e192593..823a9f19b 100644 --- a/pkg/strings/sortedSlice_test.go +++ b/pkg/strings/sortedSlice_test.go @@ -335,7 +335,7 @@ func TestSortedSlice_Intersection(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := tt.slice.Intersection(tt.args.second) - require.Equal(t, got, tt.want) + require.Equal(t, tt.want, got) }) } } @@ -392,7 +392,7 @@ func TestSortedSlice_Equal(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := tt.slice.Equal(tt.args.second) - require.Equal(t, got, tt.want) + require.Equal(t, tt.want, got) }) } } @@ -473,7 +473,7 @@ func TestSortedSlice_IsSuperslice(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := tt.slice.IsSuperslice(tt.args.s) - require.Equal(t, got, tt.want) + require.Equal(t, tt.want, got) }) } } diff --git a/pkg/strings/unescape.go b/pkg/strings/unescape.go new file mode 100644 index 000000000..5e879347d --- /dev/null +++ b/pkg/strings/unescape.go @@ -0,0 +1,147 @@ +package strings + +import ( + "strconv" + "strings" +) + +type MalformedSequenceError string + +func (e MalformedSequenceError) Error() string { + return "malformed path escape " + strconv.Quote(string(e)) +} + +// UnescapingMode defines the behavior of ServeMux when unescaping path parameters. +type UnescapingMode int + +const ( + // UnescapingModeAllExceptReserved unescapes all path parameters except RFC 6570 + // reserved characters. + UnescapingModeAllExceptReserved UnescapingMode = 1 + + // UnescapingModeAllExceptSlash unescapes URL path parameters except path + // separators, which will be left as "%2F". + UnescapingModeAllExceptSlash UnescapingMode = 2 + + // UnescapingModeAllCharacters unescapes all URL path parameters. + UnescapingModeAllCharacters UnescapingMode = 3 +) + +/* + * The following code is adopted and modified from Go's standard library + * and carries the attached license. + * + * Copyright 2009 The Go Authors. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +// isHex returns whether or not the given byte is a valid hex character +func isHex(c byte) bool { + switch { + case '0' <= c && c <= '9': + return true + case 'a' <= c && c <= 'f': + return true + case 'A' <= c && c <= 'F': + return true + } + return false +} + +func isRFC6570Reserved(c byte) bool { + switch c { + case '!', '#', '$', '&', '\'', '(', ')', '*', + '+', ',', '/', ':', ';', '=', '?', '@', '[', ']': + return true + default: + return false + } +} + +// unHex converts a hex point to the bit representation +func unHex(c byte) byte { + switch { + case '0' <= c && c <= '9': + return c - '0' + case 'a' <= c && c <= 'f': + return c - 'a' + 10 + case 'A' <= c && c <= 'F': + return c - 'A' + 10 + } + return 0 +} + +// shouldUnescapeWithMode returns true if the character is escapable with the +// given mode +func shouldUnescapeWithMode(c byte, mode UnescapingMode) bool { + switch mode { + case UnescapingModeAllExceptReserved: + if isRFC6570Reserved(c) { + return false + } + case UnescapingModeAllExceptSlash: + if c == '/' { + return false + } + case UnescapingModeAllCharacters: + return true + } + return true +} + +// checkWellFormed checks if the given string is well-formed +func checkWellFormed(s string) (bool, error) { + n := 0 + for i := 0; i < len(s); { + if s[i] != '%' { + i++ + continue + } + n++ + if i+2 >= len(s) || !isHex(s[i+1]) || !isHex(s[i+2]) { + s = s[i:] + if len(s) > 3 { + s = s[:3] + } + return false, MalformedSequenceError(s) + } + i += 3 + } + return n != 0, nil +} + +// Unescape unescapes a path string using the provided mode +func Unescape(s string, mode UnescapingMode, multisegment bool) (string, error) { + if !multisegment { + mode = UnescapingModeAllCharacters + } + + // Count %, check that they're well-formed. + needEscape, err := checkWellFormed(s) + if err != nil { + return "", err + } + if !needEscape { + return s, nil + } + + var t strings.Builder + t.Grow(len(s)) + for i := 0; i < len(s); i++ { + switch s[i] { + case '%': + c := unHex(s[i+1])<<4 | unHex(s[i+2]) + if shouldUnescapeWithMode(c, mode) { + t.WriteByte(c) + i += 2 + continue + } + fallthrough + default: + t.WriteByte(s[i]) + } + } + + return t.String(), nil +} diff --git a/pkg/strings/unescape_internal_test.go b/pkg/strings/unescape_internal_test.go new file mode 100644 index 000000000..b3b4c093d --- /dev/null +++ b/pkg/strings/unescape_internal_test.go @@ -0,0 +1,84 @@ +package strings_test + +import ( + "testing" + + "github.com/plgd-dev/hub/v2/pkg/strings" + "github.com/stretchr/testify/require" +) + +func TestUnescape(t *testing.T) { + tbl := []struct { + name string + input string + mode strings.UnescapingMode + multisegment bool + expected string + expectedErr error + }{ + { + name: "No escaping required", + input: "hello world", + mode: strings.UnescapingModeAllCharacters, + multisegment: true, + expected: "hello world", + expectedErr: nil, + }, + { + name: "Single character escaping", + input: "/%20", + mode: strings.UnescapingModeAllCharacters, + multisegment: true, + expected: "/ ", + expectedErr: nil, + }, + { + name: "Multiple character escaping", + input: "hello%20world", + mode: strings.UnescapingModeAllCharacters, + multisegment: true, + expected: "hello world", + expectedErr: nil, + }, + { + name: "Invalid escape sequence", + input: "%2", + mode: strings.UnescapingModeAllCharacters, + multisegment: true, + expected: "", + expectedErr: strings.MalformedSequenceError("%2"), + }, + { + name: "Escaping except slash with multisegment=false", + input: "/%2F%23%20", + mode: strings.UnescapingModeAllExceptSlash, + multisegment: true, + expected: "/%2F# ", + expectedErr: nil, + }, + { + name: "Escaping except reserved with multisegment=true", + input: "/%2F%23%20", + mode: strings.UnescapingModeAllExceptReserved, + multisegment: true, + expected: "/%2F%23 ", + expectedErr: nil, + }, + { + name: "Escaping all characters with multisegment=true", + input: "/%2F%23%20", + mode: strings.UnescapingModeAllCharacters, + multisegment: true, + expected: "//# ", + expectedErr: nil, + }, + } + + for _, test := range tbl { + t.Run(test.name, func(t *testing.T) { + result, err := strings.Unescape(test.input, test.mode, test.multisegment) + require.Equal(t, test.expected, result) + require.Equal(t, test.expectedErr, err) + }) + } +} diff --git a/pkg/sync/task/future/future_test.go b/pkg/sync/task/future/future_test.go index adce8e2e1..452a9edd9 100644 --- a/pkg/sync/task/future/future_test.go +++ b/pkg/sync/task/future/future_test.go @@ -2,12 +2,13 @@ package future import ( "context" - "fmt" + "errors" "sync" "testing" "time" "github.com/plgd-dev/hub/v2/test/config" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -29,7 +30,7 @@ func TestFutureReadyAfterError(t *testing.T) { fut, set := New() require.False(t, fut.Ready()) - set(nil, fmt.Errorf("test error")) + set(nil, errors.New("test error")) require.True(t, fut.Ready()) val, err := fut.Get(context.Background()) @@ -60,8 +61,8 @@ func TestFutureGetMultithreaded(t *testing.T) { go func() { defer wg.Done() value, err := fut.Get(ctx) - require.NoError(t, err) - require.Equal(t, val, value.(string)) + assert.NoError(t, err) + assert.Equal(t, val, value.(string)) }() } diff --git a/pkg/sync/task/queue/queue.go b/pkg/sync/task/queue/queue.go index 29a9bdfcf..da64612e9 100644 --- a/pkg/sync/task/queue/queue.go +++ b/pkg/sync/task/queue/queue.go @@ -2,7 +2,7 @@ package queue import ( "container/list" - "fmt" + "errors" "sync" "github.com/panjf2000/ants/v2" @@ -21,7 +21,7 @@ type Queue struct { // New creates task queue which is processed by goroutines. func New(cfg Config) (*Queue, error) { if cfg.Size <= 0 { - return nil, fmt.Errorf("invalid value of Size") + return nil, errors.New("invalid value of Size") } p, err := ants.NewPool(cfg.GoPoolSize, ants.WithPreAlloc(true), ants.WithExpiryDuration(cfg.MaxIdleTime), ants.WithNonblocking(true)) if err != nil { @@ -38,7 +38,7 @@ func (q *Queue) appendQueue(tasks []func()) error { q.mutex.Lock() defer q.mutex.Unlock() if q.queue.Len()+len(tasks) > q.limit { - return fmt.Errorf("reached limit of max processed jobs") + return errors.New("reached limit of max processed jobs") } for _, t := range tasks { q.queue.PushBack(t) diff --git a/pkg/yaml/yaml_test.go b/pkg/yaml/yaml_test.go index 68a0833a0..f2eb5b74f 100644 --- a/pkg/yaml/yaml_test.go +++ b/pkg/yaml/yaml_test.go @@ -131,7 +131,7 @@ func TestMergeYamlNodes(t *testing.T) { // merge the nodes got, err := MergeYamlNodes(tt.args.node1, tt.args.node2) if tt.wantErr { - assert.Error(t, err) + require.Error(t, err) return } require.NoError(t, err) diff --git a/resource-aggregate/commands/commands.pb.go b/resource-aggregate/commands/commands.pb.go index 9bd65d903..07df1d8b8 100644 --- a/resource-aggregate/commands/commands.pb.go +++ b/resource-aggregate/commands/commands.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: resource-aggregate/pb/commands.proto package commands @@ -503,6 +503,7 @@ type NotifyResourceChangedRequest struct { CommandMetadata *CommandMetadata `protobuf:"bytes,3,opt,name=command_metadata,json=commandMetadata,proto3" json:"command_metadata,omitempty"` Status Status `protobuf:"varint,4,opt,name=status,proto3,enum=resourceaggregate.pb.Status" json:"status,omitempty"` Etag []byte `protobuf:"bytes,5,opt,name=etag,proto3" json:"etag,omitempty"` + ResourceTypes []string `protobuf:"bytes,6,rep,name=resource_types,json=resourceTypes,proto3" json:"resource_types,omitempty"` } func (x *NotifyResourceChangedRequest) Reset() { @@ -572,6 +573,13 @@ func (x *NotifyResourceChangedRequest) GetEtag() []byte { return nil } +func (x *NotifyResourceChangedRequest) GetResourceTypes() []string { + if x != nil { + return x.ResourceTypes + } + return nil +} + type NotifyResourceChangedResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1783,11 +1791,12 @@ type Connection struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Status Connection_Status `protobuf:"varint,1,opt,name=status,proto3,enum=resourceaggregate.pb.Connection_Status" json:"status,omitempty"` - Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` // when status is ONLINE, this field contains the connection id. To update state offline, this field must be same as the one in the previous message. - ConnectedAt int64 `protobuf:"varint,4,opt,name=connected_at,json=connectedAt,proto3" json:"connected_at,omitempty"` // timestamp when the device was connected - Protocol Connection_Protocol `protobuf:"varint,5,opt,name=protocol,proto3,enum=resourceaggregate.pb.Connection_Protocol" json:"protocol,omitempty"` // application protocol. It need to be set when the status is ONLINE. - ServiceId string `protobuf:"bytes,6,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` // The service.ID, which identify the device being served, must be set when the status is ONLINE. However, during an OFFLINE event, they will be sed to empty values. + Status Connection_Status `protobuf:"varint,1,opt,name=status,proto3,enum=resourceaggregate.pb.Connection_Status" json:"status,omitempty"` + Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` // when status is ONLINE, this field contains the connection id. To update state offline, this field must be same as the one in the previous message. + ConnectedAt int64 `protobuf:"varint,4,opt,name=connected_at,json=connectedAt,proto3" json:"connected_at,omitempty"` // timestamp when the device was connected + Protocol Connection_Protocol `protobuf:"varint,5,opt,name=protocol,proto3,enum=resourceaggregate.pb.Connection_Protocol" json:"protocol,omitempty"` // application protocol. It need to be set when the status is ONLINE. + ServiceId string `protobuf:"bytes,6,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` // The service.ID, which identify the device being served, must be set when the status is ONLINE. However, during an OFFLINE event, they will be sed to empty values. + LocalEndpoints []string `protobuf:"bytes,7,rep,name=local_endpoints,json=localEndpoints,proto3" json:"local_endpoints,omitempty"` // The last local endpoints of the device, and it is set when the status is ONLINE. } func (x *Connection) Reset() { @@ -1857,6 +1866,13 @@ func (x *Connection) GetServiceId() string { return "" } +func (x *Connection) GetLocalEndpoints() []string { + if x != nil { + return x.LocalEndpoints + } + return nil +} + type TwinSynchronization struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2890,7 +2906,7 @@ var file_resource_aggregate_pb_commands_proto_rawDesc = []byte{ 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, - 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xb6, 0x02, 0x0a, + 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xdd, 0x02, 0x0a, 0x1c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, @@ -2910,266 +2926,271 @@ var file_resource_aggregate_pb_commands_proto_rawDesc = []byte{ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x68, 0x0a, 0x1d, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, + 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, 0x68, 0x0a, 0x1d, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, + 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, + 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x6d, 0x0a, 0x21, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x48, 0x0a, 0x05, 0x62, + 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, + 0x62, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x05, + 0x62, 0x61, 0x74, 0x63, 0x68, 0x22, 0x6d, 0x0a, 0x22, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x61, + 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x22, 0xdd, 0x02, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, + 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, + 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, + 0x76, 0x65, 0x12, 0x50, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x82, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, + 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, + 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, + 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xc9, 0x02, 0x0a, 0x1c, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, + 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x12, 0x50, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x68, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, - 0x6d, 0x0a, 0x21, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x48, 0x0a, 0x05, 0x62, 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x05, 0x62, 0x61, 0x74, 0x63, 0x68, 0x22, 0x6d, - 0x0a, 0x22, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, + 0xba, 0x02, 0x0a, 0x17, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, + 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, + 0x6c, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, + 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x12, 0x50, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, + 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x84, 0x01, 0x0a, + 0x18, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, + 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x22, 0xdf, 0x02, 0x0a, 0x1e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, - 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xdd, 0x02, - 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, - 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, - 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, - 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x12, 0x50, 0x0a, 0x10, 0x63, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x82, 0x01, - 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, - 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, - 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x78, 0x74, 0x22, 0xc9, 0x02, 0x0a, 0x1c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x34, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x50, 0x0a, 0x10, - 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x68, - 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, - 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, - 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xba, 0x02, 0x0a, 0x17, 0x52, 0x65, 0x74, - 0x72, 0x69, 0x65, 0x76, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2d, - 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, - 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x12, + 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, + 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x50, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, - 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x84, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, - 0x76, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, - 0x74, 0x69, 0x6c, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, - 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xdf, 0x02, 0x0a, - 0x1e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, - 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, - 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, - 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, - 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x50, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, - 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x6a, - 0x0a, 0x1f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x61, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x6a, 0x0a, 0x1f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, + 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x22, 0xa4, 0x02, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, + 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, + 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, + 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x12, 0x50, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x22, 0x82, 0x01, 0x0a, 0x16, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, + 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, + 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, + 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xc9, 0x02, + 0x0a, 0x1c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, + 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, - 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xa4, 0x02, 0x0a, 0x15, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x20, - 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, - 0x12, 0x50, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, - 0x65, 0x22, 0x82, 0x01, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x47, 0x0a, - 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, - 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xc9, 0x02, 0x0a, 0x1c, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x72, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, - 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, - 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, + 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x50, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x68, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, + 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x22, 0xae, 0x02, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, + 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, + 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x12, 0x50, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x22, 0x68, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, - 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xae, 0x02, 0x0a, - 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, + 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, + 0x76, 0x65, 0x12, 0x50, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x82, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, + 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, + 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, + 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xc9, 0x02, 0x0a, 0x1c, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, + 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, - 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, - 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x12, 0x50, 0x0a, 0x10, 0x63, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x82, 0x01, - 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, - 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, - 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x78, 0x74, 0x22, 0xc9, 0x02, 0x0a, 0x1c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x34, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x12, 0x50, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x50, 0x0a, 0x10, - 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x68, - 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, - 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, - 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xf7, 0x02, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, - 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x45, 0x0a, 0x08, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x68, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, - 0x64, 0x22, 0x21, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x4f, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, + 0xa0, 0x03, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x12, 0x45, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, + 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x73, 0x22, 0x21, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x4f, 0x46, 0x46, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x4e, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x01, 0x22, 0x52, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, diff --git a/resource-aggregate/commands/resources.pb.go b/resource-aggregate/commands/resources.pb.go index 18759a891..55b1166be 100644 --- a/resource-aggregate/commands/resources.pb.go +++ b/resource-aggregate/commands/resources.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: resource-aggregate/pb/resources.proto package commands diff --git a/resource-aggregate/commands/utils.go b/resource-aggregate/commands/utils.go index 33ed82e69..b0b973438 100644 --- a/resource-aggregate/commands/utils.go +++ b/resource-aggregate/commands/utils.go @@ -18,20 +18,20 @@ const ( // ToUUID converts resource href and device id to unique resource ID func (r *ResourceId) ToUUID() uuid.UUID { - if len(r.Href) == 0 { + if len(r.GetHref()) == 0 { return uuid.Nil } - return uuid.NewSHA1(uuid.NameSpaceURL, []byte(r.DeviceId+r.Href)) + return uuid.NewSHA1(uuid.NameSpaceURL, []byte(r.GetDeviceId()+r.GetHref())) } // ToUUID converts resource href and device id to unique resource ID func (r *Resource) ToUUID() uuid.UUID { - return uuid.NewSHA1(uuid.NameSpaceURL, []byte(r.DeviceId+r.Href)) + return uuid.NewSHA1(uuid.NameSpaceURL, []byte(r.GetDeviceId()+r.GetHref())) } // GetResourceID converts resource href and device id to resource id struct func (r *Resource) GetResourceID() *ResourceId { - return &ResourceId{DeviceId: r.DeviceId, Href: r.Href} + return &ResourceId{DeviceId: r.GetDeviceId(), Href: r.GetHref()} } func MakeLinksResourceUUID(deviceID string) uuid.UUID { @@ -138,24 +138,25 @@ func (r *ResourceId) Equal(r1 *ResourceId) bool { if r == nil || r1 == nil { return false } - return r.DeviceId == r1.DeviceId && r.Href == r1.Href + return r.GetDeviceId() == r1.GetDeviceId() && r.GetHref() == r1.GetHref() } func (r *ResourceId) ToString() string { if r == nil { return "" } - if r.DeviceId == "" { + deviceID := r.GetDeviceId() + if deviceID == "" { return "" } - if r.Href == "" { + href := r.GetHref() + if href == "" { return "" } - href := r.Href if href[0] != '/' { href = "/" + href } - return r.DeviceId + href + return deviceID + href } func ResourceIdFromString(v string) *ResourceId { diff --git a/resource-aggregate/cqrs/aggregate/aggregate.go b/resource-aggregate/cqrs/aggregate/aggregate.go index 3e73e7699..bec81ca0f 100644 --- a/resource-aggregate/cqrs/aggregate/aggregate.go +++ b/resource-aggregate/cqrs/aggregate/aggregate.go @@ -29,7 +29,7 @@ func NewDefaultRetryFunc(limit int) RetryFunc { counter := new(int) return func() (time.Time, error) { if *counter >= limit { - return time.Time{}, fmt.Errorf("retry reach limit") + return time.Time{}, errors.New("retry reach limit") } *counter++ return time.Now().Add(time.Millisecond * 10), nil @@ -37,20 +37,26 @@ func NewDefaultRetryFunc(limit int) RetryFunc { } // FactoryModelFunc creates model for aggregate -type FactoryModelFunc = func(ctx context.Context) (AggregateModel, error) +type FactoryModelFunc = func(ctx context.Context, groupID, aggregateID string) (AggregateModel, error) // Aggregate holds data for Handle command type Aggregate struct { - groupID string - aggregateID string - store eventstore.EventStore - retryFunc RetryFunc - factoryModel FactoryModelFunc - LogDebugfFunc eventstore.LogDebugfFunc + groupID string + aggregateID string + store eventstore.EventStore + retryFunc RetryFunc + factoryModel FactoryModelFunc + LogDebugfFunc eventstore.LogDebugfFunc + additionalModels []AdditionalModel +} + +type AdditionalModel struct { + GroupID string + AggregateID string } // NewAggregate creates aggregate. it load and store events created from commands -func NewAggregate(groupID, aggregateID string, retryFunc RetryFunc, store eventstore.EventStore, factoryModel FactoryModelFunc, logDebugfFunc eventstore.LogDebugfFunc) (*Aggregate, error) { +func NewAggregate(groupID, aggregateID string, retryFunc RetryFunc, store eventstore.EventStore, factoryModel FactoryModelFunc, logDebugfFunc eventstore.LogDebugfFunc, additionalModels ...AdditionalModel) (*Aggregate, error) { if groupID == "" { return nil, errors.New("cannot create aggregate: invalid groupID") } @@ -65,12 +71,13 @@ func NewAggregate(groupID, aggregateID string, retryFunc RetryFunc, store events } return &Aggregate{ - groupID: groupID, - aggregateID: aggregateID, - store: store, - factoryModel: factoryModel, - retryFunc: retryFunc, - LogDebugfFunc: logDebugfFunc, + groupID: groupID, + aggregateID: aggregateID, + store: store, + factoryModel: factoryModel, + retryFunc: retryFunc, + LogDebugfFunc: logDebugfFunc, + additionalModels: additionalModels, }, nil } @@ -130,28 +137,55 @@ func HandleRetry(ctx context.Context, retryFunc RetryFunc) error { select { case <-time.After(time.Until(when)): case <-ctx.Done(): - return fmt.Errorf("retry canceled") + return errors.New("retry canceled") } return nil } -func NewAggregateModel(ctx context.Context, groupID, aggregateID string, store eventstore.EventStore, logDebugfFunc eventstore.LogDebugfFunc, model AggregateModel) (*AggregateModelWrapper, error) { +func NewAggregateModel(ctx context.Context, groupID, aggregateID string, store eventstore.EventStore, logDebugfFunc eventstore.LogDebugfFunc, factoryModel FactoryModelFunc, additionalModels ...AdditionalModel) (*AggregateModelWrapper, error) { + models := make(map[string]AggregateModel, 1+len(additionalModels)) + model, err := factoryModel(ctx, groupID, aggregateID) + if err != nil { + return nil, fmt.Errorf("cannot create aggregate model: %w", err) + } + models[aggregateID] = model amodel := &AggregateModelWrapper{model: model} - ep := eventstore.NewProjection(store, func(ctx context.Context, groupID, aggregateID string) (eventstore.Model, error) { return amodel, nil }, logDebugfFunc) - err := ep.Project(ctx, []eventstore.SnapshotQuery{ - { - GroupID: groupID, - AggregateID: aggregateID, - }, + for _, r := range additionalModels { + model, err = factoryModel(ctx, r.GroupID, r.AggregateID) + if err != nil { + return nil, fmt.Errorf("cannot create aggregate model: %w", err) + } + models[r.AggregateID] = model + } + ep := eventstore.NewProjection(store, func(_ context.Context, _, projectionAggregateID string) (eventstore.Model, error) { + if projectionAggregateID == aggregateID { + return amodel, nil + } + if model, ok := models[projectionAggregateID]; ok { + return model, nil + } + return nil, fmt.Errorf("cannot create aggregate model for %v %v : not found", groupID, aggregateID) + }, logDebugfFunc) + q := make([]eventstore.SnapshotQuery, 0, 1+len(additionalModels)) + q = append(q, eventstore.SnapshotQuery{ + GroupID: groupID, + AggregateID: aggregateID, }) + for _, r := range additionalModels { + q = append(q, eventstore.SnapshotQuery{ + GroupID: r.GroupID, + AggregateID: r.AggregateID, + }) + } + err = ep.Project(ctx, q) if err != nil { return nil, fmt.Errorf("cannot load aggregate model: %w", err) } return amodel, nil } -func (a *Aggregate) FactoryModel(ctx context.Context) (AggregateModel, error) { - return a.factoryModel(ctx) +func (a *Aggregate) FactoryModel(ctx context.Context, groupID, aggregateID string) (AggregateModel, error) { + return a.factoryModel(ctx, groupID, aggregateID) } func (a *Aggregate) HandleCommandWithAggregateModelWrapper(ctx context.Context, cmd Command, amodel *AggregateModelWrapper) (events []eventstore.Event, concurrencyExcpetion bool, err error) { @@ -169,7 +203,7 @@ func (a *Aggregate) HandleCommandWithAggregateModelWrapper(ctx context.Context, } snapshot, ok := amodel.TakeSnapshot(newVersion + uint64(len(newEvents)-1)) if !ok { - return nil, false, fmt.Errorf("cannot take snapshot") + return nil, false, errors.New("cannot take snapshot") } // save all events except last one, because last one will be replaced by snapshot saveEvents := make([]eventstore.Event, 0, len(newEvents)) @@ -206,12 +240,7 @@ func (a *Aggregate) HandleCommand(ctx context.Context, cmd Command) ([]eventstor } firstIteration = false - model, err := a.factoryModel(ctx) - if err != nil { - return nil, errHandleCommand(err) - } - - amodel, err := NewAggregateModel(ctx, a.groupID, a.aggregateID, a.store, a.LogDebugfFunc, model) + amodel, err := NewAggregateModel(ctx, a.groupID, a.aggregateID, a.store, a.LogDebugfFunc, a.factoryModel, a.additionalModels...) if err != nil { return nil, errHandleCommand(err) } diff --git a/resource-aggregate/cqrs/aggregate/aggregateParallel_test.go b/resource-aggregate/cqrs/aggregate/aggregateParallel_test.go index d1388b868..0189f7496 100644 --- a/resource-aggregate/cqrs/aggregate/aggregateParallel_test.go +++ b/resource-aggregate/cqrs/aggregate/aggregateParallel_test.go @@ -19,6 +19,7 @@ import ( "github.com/plgd-dev/hub/v2/resource-aggregate/cqrs/eventstore/mongodb" "github.com/plgd-dev/hub/v2/resource-aggregate/events" "github.com/plgd-dev/hub/v2/test/config" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace/noop" "go.uber.org/atomic" @@ -65,7 +66,7 @@ func testNewEventstore(ctx context.Context, t *testing.T) (eventstore.EventStore func cleanUpToSnapshot(ctx context.Context, t *testing.T, store eventstore.EventStore, evs []eventstore.Event) { for _, event := range evs { if err := store.RemoveUpToVersion(ctx, []eventstore.VersionQuery{{GroupID: event.GroupID(), AggregateID: event.AggregateID(), Version: event.Version()}}); err != nil && !errors.Is(err, eventstore.ErrNotSupported) { - require.NoError(t, err) + assert.NoError(t, err) } fmt.Printf("snapshot at version %v\n", event.Version()) } @@ -82,8 +83,8 @@ func TestParallelRequest(t *testing.T) { href := "/test/resource/1" newAggregate := func(deviceID, href string) *aggregate.Aggregate { - a, err := aggregate.NewAggregate(deviceID, commands.NewResourceID(deviceID, href).ToUUID().String(), aggregate.NewDefaultRetryFunc(64), store, func(context.Context) (aggregate.AggregateModel, error) { - ev := events.NewResourceStateSnapshotTakenForCommand("test", "test", "hubID") + a, err := aggregate.NewAggregate(deviceID, commands.NewResourceID(deviceID, href).ToUUID().String(), aggregate.NewDefaultRetryFunc(128), store, func(context.Context, string, string) (aggregate.AggregateModel, error) { + ev := events.NewResourceStateSnapshotTakenForCommand("test", "test", "hubID", nil) ev.ResourceId = commands.NewResourceID(deviceID, href) return ev, nil }, nil) diff --git a/resource-aggregate/cqrs/aggregate/aggregate_test.go b/resource-aggregate/cqrs/aggregate/aggregate_test.go index 4b5a8a092..aed8ee43c 100644 --- a/resource-aggregate/cqrs/aggregate/aggregate_test.go +++ b/resource-aggregate/cqrs/aggregate/aggregate_test.go @@ -75,7 +75,7 @@ func TestAggregate(t *testing.T) { } newAggregate := func(deviceID, href string) *aggregate.Aggregate { - a, err := aggregate.NewAggregate(deviceID, commands.NewResourceID(deviceID, href).ToUUID().String(), aggregate.NewDefaultRetryFunc(1), store, func(context.Context) (aggregate.AggregateModel, error) { + a, err := aggregate.NewAggregate(deviceID, commands.NewResourceID(deviceID, href).ToUUID().String(), aggregate.NewDefaultRetryFunc(1), store, func(context.Context, string, string) (aggregate.AggregateModel, error) { return &raTest.Snapshot{DeviceId: deviceID, Href: href, IsPublished: true}, nil }, nil) require.NoError(t, err) @@ -134,10 +134,8 @@ func TestAggregate(t *testing.T) { require.NoError(t, err) concurrencyExcepTestA := newAggregate(commandPub1.GetDeviceId(), commandPub1.GetHref()) - model, err := concurrencyExcepTestA.FactoryModel(ctx) - require.NoError(t, err) - amodel, err := aggregate.NewAggregateModel(ctx, a.GroupID(), a.AggregateID(), store, a.LogDebugfFunc, model) + amodel, err := aggregate.NewAggregateModel(ctx, a.GroupID(), a.AggregateID(), store, a.LogDebugfFunc, concurrencyExcepTestA.FactoryModel) require.NoError(t, err) ev, concurrencyException, err := a.HandleCommandWithAggregateModelWrapper(ctx, &commandPub1, amodel) diff --git a/resource-aggregate/cqrs/aggregate/test/aggregate.go b/resource-aggregate/cqrs/aggregate/test/aggregate.go index 54b714aba..7c1078d12 100644 --- a/resource-aggregate/cqrs/aggregate/test/aggregate.go +++ b/resource-aggregate/cqrs/aggregate/test/aggregate.go @@ -13,45 +13,48 @@ import ( type Command = interface{} -func (e *Published) Version() uint64 { return e.EventVersion } +func (e *Published) Version() uint64 { return e.GetEventVersion() } func (e *Published) EventType() string { return "published" } func (e *Published) Marshal() ([]byte, error) { return proto.Marshal(e) } func (e *Published) Unmarshal(b []byte) error { return proto.Unmarshal(b, e) } func (e *Published) AggregateID() string { - return commands.NewResourceID(e.DeviceId, e.Href).ToUUID().String() + return commands.NewResourceID(e.GetDeviceId(), e.GetHref()).ToUUID().String() } -func (e *Published) GroupID() string { return e.DeviceId } +func (e *Published) GroupID() string { return e.GetDeviceId() } func (e *Published) IsSnapshot() bool { return false } -func (e *Published) Timestamp() time.Time { return time.Unix(0, e.EventTimestamp) } +func (e *Published) Timestamp() time.Time { return time.Unix(0, e.GetEventTimestamp()) } func (e *Published) ETag() *eventstore.ETagData { return nil } func (e *Published) ServiceID() (string, bool) { return "", false } +func (e *Published) Types() []string { return nil } -func (e *Unpublished) Version() uint64 { return e.EventVersion } +func (e *Unpublished) Version() uint64 { return e.GetEventVersion() } func (e *Unpublished) EventType() string { return "unpublished" } func (e *Unpublished) Marshal() ([]byte, error) { return proto.Marshal(e) } func (e *Unpublished) Unmarshal(b []byte) error { return proto.Unmarshal(b, e) } func (e *Unpublished) AggregateID() string { - return commands.NewResourceID(e.DeviceId, e.Href).ToUUID().String() + return commands.NewResourceID(e.GetDeviceId(), e.GetHref()).ToUUID().String() } -func (e *Unpublished) GroupID() string { return e.DeviceId } +func (e *Unpublished) GroupID() string { return e.GetDeviceId() } func (e *Unpublished) IsSnapshot() bool { return false } -func (e *Unpublished) Timestamp() time.Time { return time.Unix(0, e.EventTimestamp) } +func (e *Unpublished) Timestamp() time.Time { return time.Unix(0, e.GetEventTimestamp()) } func (e *Unpublished) ETag() *eventstore.ETagData { return nil } func (e *Unpublished) ServiceID() (string, bool) { return "", false } +func (e *Unpublished) Types() []string { return nil } -func (e *Snapshot) Version() uint64 { return e.EventVersion } +func (e *Snapshot) Version() uint64 { return e.GetEventVersion() } func (e *Snapshot) EventType() string { return "snapshot" } func (e *Snapshot) Marshal() ([]byte, error) { return proto.Marshal(e) } func (e *Snapshot) Unmarshal(b []byte) error { return proto.Unmarshal(b, e) } func (e *Snapshot) AggregateID() string { - return commands.NewResourceID(e.DeviceId, e.Href).ToUUID().String() + return commands.NewResourceID(e.GetDeviceId(), e.GetHref()).ToUUID().String() } -func (e *Snapshot) GroupId() string { return e.DeviceId } -func (e *Snapshot) GroupID() string { return e.DeviceId } +func (e *Snapshot) GroupId() string { return e.GetDeviceId() } +func (e *Snapshot) GroupID() string { return e.GetDeviceId() } func (e *Snapshot) IsSnapshot() bool { return true } -func (e *Snapshot) Timestamp() time.Time { return time.Unix(0, e.EventTimestamp) } +func (e *Snapshot) Timestamp() time.Time { return time.Unix(0, e.GetEventTimestamp()) } func (e *Snapshot) ETag() *eventstore.ETagData { return nil } func (e *Snapshot) ServiceID() (string, bool) { return "", false } +func (e *Snapshot) Types() []string { return nil } func (e *Snapshot) handleEvent(eu eventstore.EventUnmarshaler) error { if eu.EventType() == "" { @@ -106,13 +109,13 @@ func (e *Snapshot) HandleCommand(_ context.Context, cmd Command, newVersion uint switch req := cmd.(type) { case *Publish: e.IsPublished = true - return []eventstore.Event{&Published{DeviceId: req.DeviceId, Href: req.Href, EventVersion: newVersion}}, nil + return []eventstore.Event{&Published{DeviceId: req.GetDeviceId(), Href: req.GetHref(), EventVersion: newVersion}}, nil case *Unpublish: - if !e.IsPublished { - return nil, fmt.Errorf("not allowed to unpublish twice in tests") + if !e.GetIsPublished() { + return nil, errors.New("not allowed to unpublish twice in tests") } e.IsPublished = false - return []eventstore.Event{&Unpublished{DeviceId: req.DeviceId, Href: req.Href, EventVersion: newVersion}}, nil + return []eventstore.Event{&Unpublished{DeviceId: req.GetDeviceId(), Href: req.GetHref(), EventVersion: newVersion}}, nil } return nil, fmt.Errorf("unknown command %T", cmd) } diff --git a/resource-aggregate/cqrs/aggregate/test/aggregate_test.pb.go b/resource-aggregate/cqrs/aggregate/test/aggregate_test.pb.go index 25fb105b0..6edc3af42 100644 --- a/resource-aggregate/cqrs/aggregate/test/aggregate_test.pb.go +++ b/resource-aggregate/cqrs/aggregate/test/aggregate_test.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: resource-aggregate/cqrs/aggregate/test/aggregate_test.proto package test diff --git a/resource-aggregate/cqrs/eventbus/event.go b/resource-aggregate/cqrs/eventbus/event.go index b8af0c925..0c096f11b 100644 --- a/resource-aggregate/cqrs/eventbus/event.go +++ b/resource-aggregate/cqrs/eventbus/event.go @@ -17,6 +17,7 @@ type Event = interface { Timestamp() time.Time ETag() *eventstore.ETagData ServiceID() (string, bool) + Types() []string } // EventUnmarshaler provides event. diff --git a/resource-aggregate/cqrs/eventbus/goroutinePoolHandler_test.go b/resource-aggregate/cqrs/eventbus/goroutinePoolHandler_test.go index 9212bd802..6d81ccad1 100644 --- a/resource-aggregate/cqrs/eventbus/goroutinePoolHandler_test.go +++ b/resource-aggregate/cqrs/eventbus/goroutinePoolHandler_test.go @@ -3,11 +3,11 @@ package eventbus import ( "context" "errors" - "fmt" "testing" "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) type mockEventHandler struct { @@ -241,19 +241,19 @@ func TestGoroutinePoolHandler_Handle(t *testing.T) { eh, func(err error) { if wantErr { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) + require.NoError(t, err) } }) err := ep.Handle(tt.args.ctx, tt.args.iter) - assert.NoError(t, err) + require.NoError(t, err) select { case <-eh.processed: assert.Equal(t, tt.want, eh.events) case <-time.After(time.Millisecond * 100): if !tt.wantTimeout { - assert.NoError(t, fmt.Errorf("timeout")) + require.Fail(t, "timeout") } } }) diff --git a/resource-aggregate/cqrs/eventbus/nats/publisher/publisher_test.go b/resource-aggregate/cqrs/eventbus/nats/publisher/publisher_test.go index 312f30b67..8f95fca5c 100644 --- a/resource-aggregate/cqrs/eventbus/nats/publisher/publisher_test.go +++ b/resource-aggregate/cqrs/eventbus/nats/publisher/publisher_test.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "errors" - "fmt" "testing" "time" @@ -44,7 +43,7 @@ func TestPublisher(t *testing.T) { FlusherTimeout: time.Second * 30, }, }, fileWatcher, logger, publisher.WithMarshaler(json.Marshal)) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, publisher) defer func() { publisher.Close() @@ -55,7 +54,7 @@ func TestPublisher(t *testing.T) { logger, subscriber.WithGoPool(func(f func()) error { go f(); return nil }), subscriber.WithUnmarshaler(json.Unmarshal)) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, subscriber) defer func() { subscriber.Close() @@ -114,7 +113,7 @@ func TestPublisherJetStream(t *testing.T) { logger, subscriber.WithGoPool(func(f func()) error { go f(); return nil }), subscriber.WithUnmarshaler(json.Unmarshal)) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, subscriber) defer func() { subscriber.Close() @@ -133,6 +132,7 @@ type mockEvent struct { timestamp int64 Data string ETagI []byte + TypesI []string } func (e mockEvent) Version() uint64 { @@ -173,6 +173,10 @@ func (e mockEvent) ServiceID() (string, bool) { return "", false } +func (e mockEvent) Types() []string { + return e.TypesI +} + type mockEventHandler struct { newEvent chan mockEvent } @@ -207,7 +211,7 @@ func (eh *mockEventHandler) waitForEvent(timeout time.Duration) (mockEvent, erro case e := <-eh.newEvent: return e, nil case <-time.After(timeout): - return mockEvent{}, fmt.Errorf("timeout") + return mockEvent{}, errors.New("timeout") } } @@ -218,7 +222,7 @@ func testWaitForAnyEvent(timeout time.Duration, eh1 *mockEventHandler, eh2 *mock case e := <-eh2.newEvent: return e, nil case <-time.After(timeout): - return mockEvent{}, fmt.Errorf("timeout") + return mockEvent{}, errors.New("timeout") } } @@ -226,7 +230,7 @@ func testNewSubscription(ctx context.Context, t *testing.T, subscriber eventbus. t.Log("Subscribe to testNewSubscription") m := newMockEventHandler() ob, err := subscriber.Subscribe(ctx, subscriptionID, topics, m) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, ob) if ob == nil { return nil, nil @@ -306,11 +310,11 @@ func acceptanceTest(ctx context.Context, t *testing.T, timeout time.Duration, wa }, } - assert.Equal(t, 2, len(topics)) + require.Len(t, topics, 2) t.Log("Without subscription") err := publisher.Publish(ctx, topics[0:1], aggregateID1Path.GroupID, aggregateID1Path.AggregateID, eventsToPublish[0]) - assert.NoError(t, err) + require.NoError(t, err) time.Sleep(waitForSubscription) // Add handlers and observers. @@ -319,66 +323,66 @@ func acceptanceTest(ctx context.Context, t *testing.T, timeout time.Duration, wa time.Sleep(waitForSubscription) err = publisher.Publish(ctx, topics[0:1], aggregateID1Path.GroupID, aggregateID1Path.AggregateID, eventsToPublish[1]) - assert.NoError(t, err) + require.NoError(t, err) event0, err := m0.waitForEvent(timeout) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, eventsToPublish[1], event0) err = ob0.Close() - assert.NoError(t, err) + require.NoError(t, err) t.Log("Subscribe more observers") m1, ob1 := testNewSubscription(ctx, t, subscriber, "sub-1", topics[1:2]) defer func() { err = ob1.Close() - assert.NoError(t, err) + require.NoError(t, err) }() m2, ob2 := testNewSubscription(ctx, t, subscriber, "sub-2", topics[1:2]) defer func() { err = ob2.Close() - assert.NoError(t, err) + require.NoError(t, err) }() m3, ob3 := testNewSubscription(ctx, t, subscriber, "sub-shared", topics[0:1]) defer func() { err = ob3.Close() - assert.NoError(t, err) + require.NoError(t, err) }() m4, ob4 := testNewSubscription(ctx, t, subscriber, "sub-shared", topics[0:1]) defer func() { err = ob4.Close() - assert.NoError(t, err) + require.NoError(t, err) }() time.Sleep(waitForSubscription) err = publisher.Publish(ctx, topics, aggregateID1Path.GroupID, aggregateID1Path.AggregateID, eventsToPublish[2]) - assert.NoError(t, err) + require.NoError(t, err) event1, err := m1.waitForEvent(timeout) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, eventsToPublish[2], event1) event2, err := m2.waitForEvent(timeout) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, eventsToPublish[2], event2) event3, err := testWaitForAnyEvent(timeout, m3, m4) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, eventsToPublish[2], event3) topic := "test.new_topic_" + uuid.Must(uuid.NewRandom()).String() topics = append(topics, topic) err = ob4.SetTopics(ctx, topics) time.Sleep(waitForSubscription) - assert.NoError(t, err) + require.NoError(t, err) err = publisher.Publish(ctx, []string{topic}, aggregateID1Path.GroupID, aggregateID1Path.AggregateID, eventsToPublish[3]) - assert.NoError(t, err) + require.NoError(t, err) event4, err := m4.waitForEvent(timeout) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, eventsToPublish[3], event4) err = ob4.SetTopics(ctx, nil) - assert.NoError(t, err) + require.NoError(t, err) } diff --git a/resource-aggregate/cqrs/eventbus/nats/subscriber/reconnect_test.go b/resource-aggregate/cqrs/eventbus/nats/subscriber/reconnect_test.go index 57702f655..b5ec6891d 100644 --- a/resource-aggregate/cqrs/eventbus/nats/subscriber/reconnect_test.go +++ b/resource-aggregate/cqrs/eventbus/nats/subscriber/reconnect_test.go @@ -3,7 +3,7 @@ package subscriber_test import ( "context" "encoding/json" - "fmt" + "errors" "testing" "time" @@ -95,7 +95,7 @@ func TestSubscriberReconnect(t *testing.T) { select { case <-ch: case <-ctx.Done(): - require.NoError(t, fmt.Errorf("Timeout")) + require.NoError(t, errors.New("Timeout")) } naClient1, pub1, err := natsTest.NewClientAndPublisher(config.MakePublisherConfig(), fileWatcher, logger, publisher.WithMarshaler(json.Marshal)) require.NoError(t, err) diff --git a/resource-aggregate/cqrs/eventbus/nats/subscriber/subscriber.go b/resource-aggregate/cqrs/eventbus/nats/subscriber/subscriber.go index a7a49434a..64a6ef115 100644 --- a/resource-aggregate/cqrs/eventbus/nats/subscriber/subscriber.go +++ b/resource-aggregate/cqrs/eventbus/nats/subscriber/subscriber.go @@ -3,6 +3,7 @@ package subscriber import ( "context" "encoding/json" + "errors" "fmt" "sync" "time" @@ -146,7 +147,7 @@ func New(conn *nats.Conn, pendingLimits natsClient.PendingLimitsConfig, logger l } if cfg.dataUnmarshaler == nil { - return nil, fmt.Errorf("invalid eventUnmarshaler") + return nil, errors.New("invalid eventUnmarshaler") } s := &Subscriber{ @@ -293,7 +294,7 @@ func (o *Observer) handleMsg(msg *nats.Msg) { hasNext: true, e: &e, dataUnmarshaler: func(v interface{}) error { - return o.dataUnmarshaler(e.Data, v) + return o.dataUnmarshaler(e.GetData(), v) }, } diff --git a/resource-aggregate/cqrs/eventbus/nats/subscriber/subscriber_test.go b/resource-aggregate/cqrs/eventbus/nats/subscriber/subscriber_test.go index 4eb45c9ae..c65db81d4 100644 --- a/resource-aggregate/cqrs/eventbus/nats/subscriber/subscriber_test.go +++ b/resource-aggregate/cqrs/eventbus/nats/subscriber/subscriber_test.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "errors" - "fmt" "testing" "time" @@ -67,6 +66,7 @@ type mockEvent struct { timestamp int64 Data string ETagI []byte + TypesI []string } func (e mockEvent) Version() uint64 { @@ -107,6 +107,10 @@ func (e mockEvent) ServiceID() (string, bool) { return "", false } +func (e mockEvent) Types() []string { + return e.TypesI +} + type mockEventHandler struct { newEvent chan mockEvent } @@ -141,7 +145,7 @@ func (eh *mockEventHandler) waitForEvent(timeout time.Duration) (mockEvent, erro case e := <-eh.newEvent: return e, nil case <-time.After(timeout): - return mockEvent{}, fmt.Errorf("timeout") + return mockEvent{}, errors.New("timeout") } } @@ -152,7 +156,7 @@ func testWaitForAnyEvent(timeout time.Duration, eh1 *mockEventHandler, eh2 *mock case e := <-eh2.newEvent: return e, nil case <-time.After(timeout): - return mockEvent{}, fmt.Errorf("timeout") + return mockEvent{}, errors.New("timeout") } } @@ -243,7 +247,7 @@ func acceptanceTest(ctx context.Context, t *testing.T, timeout time.Duration, pu }, } - require.Equal(t, 2, len(publishTopics)) + require.Len(t, publishTopics, 2) t.Log("Without subscription") err := publisher.Publish(ctx, publishTopics[0:1], aggregateID1Path.GroupID, aggregateID1Path.AggregateID, eventsToPublish[0]) diff --git a/resource-aggregate/cqrs/eventbus/pb/eventbus.pb.go b/resource-aggregate/cqrs/eventbus/pb/eventbus.pb.go index 2a93dde3b..33018250f 100644 --- a/resource-aggregate/cqrs/eventbus/pb/eventbus.pb.go +++ b/resource-aggregate/cqrs/eventbus/pb/eventbus.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: resource-aggregate/cqrs/eventbus/pb/eventbus.proto package pb diff --git a/resource-aggregate/cqrs/eventstore/cqldb/delete.go b/resource-aggregate/cqrs/eventstore/cqldb/delete.go index 0a82de4d3..a5240ba60 100644 --- a/resource-aggregate/cqrs/eventstore/cqldb/delete.go +++ b/resource-aggregate/cqrs/eventstore/cqldb/delete.go @@ -2,7 +2,7 @@ package cqldb import ( "context" - "fmt" + "errors" "strings" "github.com/plgd-dev/hub/v2/pkg/cqldb" @@ -30,7 +30,7 @@ func getDeviceIDFilter(queries []eventstore.DeleteQuery) string { func (s *EventStore) Delete(ctx context.Context, queries []eventstore.DeleteQuery) error { deviceIDFilter := getDeviceIDFilter(queries) if len(deviceIDFilter) == 0 { - return fmt.Errorf("failed to delete documents: invalid query") + return errors.New("failed to delete documents: invalid query") } return s.client.Session().Query("delete from " + s.Table() + " " + cqldb.WhereClause + " " + deviceIDKey + " in (" + deviceIDFilter + ");").WithContext(ctx).Exec() diff --git a/resource-aggregate/cqrs/eventstore/cqldb/delete_test.go b/resource-aggregate/cqrs/eventstore/cqldb/delete_test.go index 51c512505..27158b12b 100644 --- a/resource-aggregate/cqrs/eventstore/cqldb/delete_test.go +++ b/resource-aggregate/cqrs/eventstore/cqldb/delete_test.go @@ -61,7 +61,7 @@ func TestEventStore_Delete(t *testing.T) { ctx := context.Background() store, err := NewTestEventStore(ctx, fileWatcher, logger) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, store) defer func() { t.Log("clearing db") diff --git a/resource-aggregate/cqrs/eventstore/cqldb/eventstore.go b/resource-aggregate/cqrs/eventstore/cqldb/eventstore.go index 5e5565a72..bd9fc0a9f 100644 --- a/resource-aggregate/cqrs/eventstore/cqldb/eventstore.go +++ b/resource-aggregate/cqrs/eventstore/cqldb/eventstore.go @@ -17,7 +17,7 @@ import ( // Document const ( - // cqldbdb has all keys in in lowercase + // cqldbdb has all keys in lowercase idKey = "id" versionKey = "version" snapshotKey = "snapshot" @@ -138,11 +138,11 @@ func encodeToBlob(data []byte) string { func getLatestEventsSnapshot(events []eventstore.Event, marshaler MarshalerFunc) (eventstore.Event, []byte, error) { if len(events) == 0 { - return nil, nil, fmt.Errorf("empty events") + return nil, nil, errors.New("empty events") } lastEvent := events[len(events)-1] if !lastEvent.IsSnapshot() { - return nil, nil, fmt.Errorf("the last event must be a snapshot") + return nil, nil, errors.New("the last event must be a snapshot") } // Marshal event data if there is any. snapshot, err := marshaler(lastEvent) diff --git a/resource-aggregate/cqrs/eventstore/cqldb/getLatestDeviceETags.go b/resource-aggregate/cqrs/eventstore/cqldb/getLatestDeviceETags.go index 147203c83..b3f052fcb 100644 --- a/resource-aggregate/cqrs/eventstore/cqldb/getLatestDeviceETags.go +++ b/resource-aggregate/cqrs/eventstore/cqldb/getLatestDeviceETags.go @@ -3,7 +3,6 @@ package cqldb import ( "context" "errors" - "fmt" "sort" "strings" @@ -40,7 +39,7 @@ func (a etagTimestamps) toETags(limit int) [][]byte { // Get latest ETags for device resources from event store for batch observing func (s *EventStore) GetLatestDeviceETags(ctx context.Context, deviceID string, limit uint32) ([][]byte, error) { if deviceID == "" { - return nil, fmt.Errorf("deviceID is invalid") + return nil, errors.New("deviceID is invalid") } var q strings.Builder q.WriteString(cqldb.SelectCommand) diff --git a/resource-aggregate/cqrs/eventstore/cqldb/getLatestDeviceETags_test.go b/resource-aggregate/cqrs/eventstore/cqldb/getLatestDeviceETags_test.go index 3147f11e1..b390d6355 100644 --- a/resource-aggregate/cqrs/eventstore/cqldb/getLatestDeviceETags_test.go +++ b/resource-aggregate/cqrs/eventstore/cqldb/getLatestDeviceETags_test.go @@ -23,7 +23,7 @@ func TestGetLatestDeviceETAG(t *testing.T) { ctx := context.Background() store, err := NewTestEventStore(ctx, fileWatcher, logger) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, store) defer func() { t.Log("clearing db") diff --git a/resource-aggregate/cqrs/eventstore/cqldb/load.go b/resource-aggregate/cqrs/eventstore/cqldb/load.go index 05172685b..d0d1b57d9 100644 --- a/resource-aggregate/cqrs/eventstore/cqldb/load.go +++ b/resource-aggregate/cqrs/eventstore/cqldb/load.go @@ -3,6 +3,7 @@ package cqldb import ( "context" "fmt" + "strconv" "strings" "github.com/gocql/gocql" @@ -166,7 +167,7 @@ func snapshotQueriesToFilter(deviceID string, queries []eventstore.SnapshotQuery } filter.WriteString(timestampKey) filter.WriteString(">=") - filter.WriteString(fmt.Sprintf("%v", timestamp)) + filter.WriteString(strconv.FormatInt(timestamp, 10)) filter.WriteString(" ALLOW FILTERING") } return filter.String() diff --git a/resource-aggregate/cqrs/eventstore/cqldb/loadDeviceMetadataByServiceIDs.go b/resource-aggregate/cqrs/eventstore/cqldb/loadDeviceMetadataByServiceIDs.go index 4319e4ec3..efb8c78f0 100644 --- a/resource-aggregate/cqrs/eventstore/cqldb/loadDeviceMetadataByServiceIDs.go +++ b/resource-aggregate/cqrs/eventstore/cqldb/loadDeviceMetadataByServiceIDs.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strconv" "strings" "github.com/gocql/gocql" @@ -19,7 +20,7 @@ func (s *EventStore) LoadDeviceMetadataByServiceIDs(ctx context.Context, service return nil, status.Errorf(codes.InvalidArgument, "invalid serviceIDs") } serviceIDs = pkgStrings.Unique(serviceIDs) - q := cqldb.SelectCommand + " " + deviceIDKey + "," + serviceIDKey + " " + cqldb.FromClause + " " + s.Table() + " " + cqldb.WhereClause + " " + serviceIDKey + " in (" + strings.Join(serviceIDs, ",") + ") LIMIT " + fmt.Sprintf("%v", limit) + ";" + q := cqldb.SelectCommand + " " + deviceIDKey + "," + serviceIDKey + " " + cqldb.FromClause + " " + s.Table() + " " + cqldb.WhereClause + " " + serviceIDKey + " in (" + strings.Join(serviceIDs, ",") + ") LIMIT " + strconv.FormatInt(limit, 10) + ";" iter := s.client.Session().Query(q).WithContext(ctx).Iter() if iter == nil { return nil, errors.New("cannot create iterator") diff --git a/resource-aggregate/cqrs/eventstore/cqldb/loadDeviceMetadataByServiceIDs_test.go b/resource-aggregate/cqrs/eventstore/cqldb/loadDeviceMetadataByServiceIDs_test.go index dc08689c5..e6f1af5c3 100644 --- a/resource-aggregate/cqrs/eventstore/cqldb/loadDeviceMetadataByServiceIDs_test.go +++ b/resource-aggregate/cqrs/eventstore/cqldb/loadDeviceMetadataByServiceIDs_test.go @@ -23,7 +23,7 @@ func TestLoadDeviceMetadataByServiceIDs(t *testing.T) { ctx := context.Background() store, err := NewTestEventStore(ctx, fileWatcher, logger) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, store) defer func() { t.Log("clearing db") diff --git a/resource-aggregate/cqrs/eventstore/cqldb/save.go b/resource-aggregate/cqrs/eventstore/cqldb/save.go index 64742c06e..9d2255c35 100644 --- a/resource-aggregate/cqrs/eventstore/cqldb/save.go +++ b/resource-aggregate/cqrs/eventstore/cqldb/save.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strconv" "strings" "github.com/gocql/gocql" @@ -54,8 +55,8 @@ func eventToKeyValues(event eventstore.Event, insert bool, data []byte) keyValue kvs = append(kvs, keyValue{Key: idKey, Val: event.AggregateID()}) kvs = append(kvs, keyValue{Key: eventTypeKey, Val: "'" + event.EventType() + "'"}) } - kvs = append(kvs, keyValue{Key: versionKey, Val: fmt.Sprintf("%v", event.Version())}) - kvs = append(kvs, keyValue{Key: timestampKey, Val: fmt.Sprintf("%v", event.Timestamp().UnixNano())}) + kvs = append(kvs, keyValue{Key: versionKey, Val: strconv.FormatUint(event.Version(), 10)}) + kvs = append(kvs, keyValue{Key: timestampKey, Val: strconv.FormatInt(event.Timestamp().UnixNano(), 10)}) kvs = append(kvs, keyValue{Key: snapshotKey, Val: encodeToBlob(data)}) serviceID, ok := event.ServiceID() if ok { @@ -69,7 +70,7 @@ func eventToKeyValues(event eventstore.Event, insert bool, data []byte) keyValue etagData := event.ETag() if etagData != nil { kvs = append(kvs, keyValue{Key: etagKey, Val: encodeToBlob(etagData.ETag)}) - kvs = append(kvs, keyValue{Key: etagTimestampKey, Val: fmt.Sprintf("%v", etagData.Timestamp)}) + kvs = append(kvs, keyValue{Key: etagTimestampKey, Val: strconv.FormatInt(etagData.Timestamp, 10)}) } else { kvs = append(kvs, keyValue{Key: etagKey, Val: "null"}) kvs = append(kvs, keyValue{Key: etagTimestampKey, Val: "0"}) @@ -88,7 +89,7 @@ func (s *EventStore) saveEvent(ctx context.Context, events []eventstore.Event) ( return eventstore.Fail, err } setters := eventsToCQLSetValue(lastEvent, snapshotBinary) - q := "update " + s.client.Keyspace() + "." + s.config.Table + " set " + setters + " " + cqldb.WhereClause + " " + deviceIDKey + "=" + lastEvent.GroupID() + " and " + idKey + "=" + lastEvent.AggregateID() + " if " + versionKey + "=" + fmt.Sprintf("%v", events[0].Version()-1) + ";" + q := "update " + s.client.Keyspace() + "." + s.config.Table + " set " + setters + " " + cqldb.WhereClause + " " + deviceIDKey + "=" + lastEvent.GroupID() + " and " + idKey + "=" + lastEvent.AggregateID() + " if " + versionKey + "=" + strconv.FormatUint(events[0].Version()-1, 10) + ";" ok, err := s.client.Session().Query(q).WithContext(ctx).ScanCAS(nil) if err != nil { return eventstore.Fail, fmt.Errorf("cannot update snapshot event('%v'): %w", events, err) @@ -108,27 +109,27 @@ func (s *EventStore) Save(ctx context.Context, events ...eventstore.Event) (even if err := eventstore.ValidateEventsBeforeSave(events); err != nil { return eventstore.Fail, err } - if events[0].Version() == 0 { - lastEvent, data, err := getLatestEventsSnapshot(events, s.config.marshalerFunc) - if err != nil { - return eventstore.Fail, err - } - kvs := eventToKeyValues(lastEvent, true, data) - keys := kvs.Keys() - values := kvs.Values() + if events[0].Version() != 0 { + return s.saveEvent(ctx, events) + } + lastEvent, data, err := getLatestEventsSnapshot(events, s.config.marshalerFunc) + if err != nil { + return eventstore.Fail, err + } + kvs := eventToKeyValues(lastEvent, true, data) + keys := kvs.Keys() + values := kvs.Values() - q := "insert into " + s.Table() + " (" + strings.Join(keys, ",") + ") values (" + strings.Join(values, ",") + ") if not exists;" - ok, err := s.client.Session().Query(q).WithContext(ctx).ScanCAS(nil, nil, nil, nil, nil, nil, nil, nil, nil) - if err != nil { - if errors.Is(err, gocql.ErrNotFound) { - return eventstore.Ok, nil - } - return eventstore.Fail, fmt.Errorf("cannot insert first events('%v'): %w", events, err) - } - if !ok { - return eventstore.ConcurrencyException, nil + q := "insert into " + s.Table() + " (" + strings.Join(keys, ",") + ") values (" + strings.Join(values, ",") + ") if not exists;" + ok, err := s.client.Session().Query(q).WithContext(ctx).ScanCAS(nil, nil, nil, nil, nil, nil, nil, nil, nil) + if err != nil { + if errors.Is(err, gocql.ErrNotFound) { + return eventstore.Ok, nil } - return eventstore.Ok, nil + return eventstore.Fail, fmt.Errorf("cannot insert first events('%v'): %w", events, err) } - return s.saveEvent(ctx, events) + if !ok { + return eventstore.ConcurrencyException, nil + } + return eventstore.Ok, nil } diff --git a/resource-aggregate/cqrs/eventstore/event.go b/resource-aggregate/cqrs/eventstore/event.go index 68d4d3e18..10065bf49 100644 --- a/resource-aggregate/cqrs/eventstore/event.go +++ b/resource-aggregate/cqrs/eventstore/event.go @@ -2,6 +2,7 @@ package eventstore import ( "context" + "errors" "fmt" "time" @@ -23,6 +24,7 @@ type Event = interface { ServiceID() (string, bool) Timestamp() time.Time ETag() *ETagData + Types() []string } // EventUnmarshaler provides event. @@ -153,7 +155,7 @@ func validateFirstEvent(event Event) error { } if event.Timestamp().IsZero() { - return fmt.Errorf("invalid zero events[0].Timestamp") + return errors.New("invalid zero events[0].Timestamp") } return nil diff --git a/resource-aggregate/cqrs/eventstore/event_test.go b/resource-aggregate/cqrs/eventstore/event_test.go index 3d3ce3179..7b2c3348a 100644 --- a/resource-aggregate/cqrs/eventstore/event_test.go +++ b/resource-aggregate/cqrs/eventstore/event_test.go @@ -14,6 +14,7 @@ type mockEvent struct { etagData *ETagData isSnapshot bool serviceID string + types []string } func (e *mockEvent) AggregateID() string { @@ -51,6 +52,10 @@ func (e *mockEvent) IsSnapshot() bool { return e.isSnapshot } +func (e *mockEvent) Types() []string { + return e.types +} + func TestValidateEventsBeforeSave(t *testing.T) { ev := mockEvent{ aggregateID: "d9e7e4a0-49b7-4e6e-8f00-9ebefb3f6f5d", diff --git a/resource-aggregate/cqrs/eventstore/eventstore.go b/resource-aggregate/cqrs/eventstore/eventstore.go index a67bd9c31..c6f0a2e02 100644 --- a/resource-aggregate/cqrs/eventstore/eventstore.go +++ b/resource-aggregate/cqrs/eventstore/eventstore.go @@ -2,7 +2,7 @@ package eventstore import ( "context" - "fmt" + "errors" ) // VersionQuery used to load events from version. @@ -14,15 +14,17 @@ type VersionQuery struct { // SnapshotQuery used to load events from snapshot. type SnapshotQuery struct { - GroupID string // filter by group ID - AggregateID string // filter to certain aggregateID, groupID is required + GroupID string // filter by group ID + AggregateID string // filter to certain aggregateID, groupID is required + Types []string // filter to certain event types, optional } // Get events with given attributes. // All filtering options are optional, if none are given then all events are returned, type GetEventsQuery struct { - GroupID string // filter by group ID, optional - AggregateID string // filter to certain aggregateID, optional + GroupID string // filter by group ID, optional + AggregateID string // filter to certain aggregateID, optional + Types []string // filter to certain event types, optional } // Delete documents with given group id @@ -69,4 +71,4 @@ type EventStore interface { } // ErrNotSupported is returned when the operation is not supported. -var ErrNotSupported = fmt.Errorf("not supported") +var ErrNotSupported = errors.New("not supported") diff --git a/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_events_test.go b/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_events_test.go index 4c62467b8..15a0aa328 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_events_test.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_events_test.go @@ -3,7 +3,6 @@ package mongodb_test import ( "context" "errors" - "fmt" "reflect" "sort" "sync" @@ -20,7 +19,7 @@ var ( UserId: "userId", } - errCannotUnmarshalEvent = fmt.Errorf("cannot unmarshal event") + errCannotUnmarshalEvent = errors.New("cannot unmarshal event") ) func MakeResourceLinksPublishedEvent(resources []*commands.Resource, deviceID string, eventMetadata *events.EventMetadata) eventstore.EventUnmarshaler { @@ -423,15 +422,16 @@ func MakeDeviceMetadata(deviceID string, deviceMetadataUpdated *events.DeviceMet } type MockEvent struct { - VersionI uint64 `bson:"version"` - EventTypeI string `bson:"eventtype"` - IsSnapshotI bool `bson:"issnapshot"` - AggregateIDI string `bson:"aggregateid"` - GroupIDI string `bson:"groupid"` - DataI []byte `bson:"data"` - TimestampI int64 `bson:"timestamp"` - ETagI []byte `bson:"etag"` - ServiceIDI string `bson:"serviceid"` + VersionI uint64 `bson:"version"` + EventTypeI string `bson:"eventtype"` + IsSnapshotI bool `bson:"issnapshot"` + AggregateIDI string `bson:"aggregateid"` + GroupIDI string `bson:"groupid"` + DataI []byte `bson:"data"` + TimestampI int64 `bson:"timestamp"` + ETagI []byte `bson:"etag"` + ServiceIDI string `bson:"serviceid"` + ResourceTypesI []string `bson:"resourcetypes"` } func (e MockEvent) Version() uint64 { @@ -472,6 +472,10 @@ func (e MockEvent) ServiceID() (string, bool) { return e.ServiceIDI, true } +func (e MockEvent) Types() []string { + return e.ResourceTypesI +} + type MockEventHandler struct { lock sync.Mutex events map[string]map[string][]eventstore.Event @@ -481,6 +485,14 @@ func NewMockEventHandler() *MockEventHandler { return &MockEventHandler{events: make(map[string]map[string][]eventstore.Event)} } +func (eh *MockEventHandler) PopEvents() map[string]map[string][]eventstore.Event { + eh.lock.Lock() + defer eh.lock.Unlock() + events := eh.events + eh.events = make(map[string]map[string][]eventstore.Event) + return events +} + func (eh *MockEventHandler) SetElement(groupID, aggregateID string, e MockEvent) { var device map[string][]eventstore.Event var ok bool diff --git a/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_eventstore_test.go b/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_eventstore_test.go index 90bebaac3..8135ac720 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_eventstore_test.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_eventstore_test.go @@ -3,7 +3,6 @@ package mongodb_test import ( "context" "errors" - "fmt" "github.com/plgd-dev/hub/v2/resource-aggregate/cqrs/eventstore" ) @@ -132,7 +131,7 @@ func (s *MockEventStore) LoadFromSnapshot(ctx context.Context, queries []eventst ret = append(ret, q) } if len(ret) == 0 { - return fmt.Errorf("cannot load events: not found") + return errors.New("cannot load events: not found") } return s.LoadFromVersion(ctx, ret, eventHandler) diff --git a/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_test.go b/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_test.go index e228170d8..229540a5c 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_test.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/acceptance_testing_test.go @@ -298,7 +298,7 @@ func AcceptanceTest(ctx context.Context, t *testing.T, store eventstore.EventSto eh1 := NewMockEventHandler() err = store.LoadFromSnapshot(ctx, []eventstore.SnapshotQuery{{GroupID: "notExist"}}, eh1) require.NoError(t, err) - require.Equal(t, 0, len(eh1.events)) + require.Empty(t, eh1.events) t.Log("load events") eh2 := NewMockEventHandler() @@ -392,7 +392,7 @@ func AcceptanceTest(ctx context.Context, t *testing.T, store eventstore.EventSto }, }, eh8) require.NoError(t, err) - require.Equal(t, 0, len(eh8.events[aggregateID1Path.GroupID][aggregateID1Path.AggregateID])) + require.Empty(t, eh8.events[aggregateID1Path.GroupID][aggregateID1Path.AggregateID]) t.Log("load events up to version without version specified") eh9 := NewMockEventHandler() @@ -403,7 +403,7 @@ func AcceptanceTest(ctx context.Context, t *testing.T, store eventstore.EventSto }, }, eh9) require.NoError(t, err) - require.Equal(t, 0, len(eh9.events[aggregateID1Path.GroupID][aggregateID1Path.AggregateID])) + require.Empty(t, eh9.events[aggregateID1Path.GroupID][aggregateID1Path.AggregateID]) t.Log("test projection all") model := NewMockEventHandler() diff --git a/resource-aggregate/cqrs/eventstore/mongodb/delete.go b/resource-aggregate/cqrs/eventstore/mongodb/delete.go index cb73ab476..80bf60d53 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/delete.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/delete.go @@ -2,7 +2,7 @@ package mongodb import ( "context" - "fmt" + "errors" "github.com/plgd-dev/hub/v2/resource-aggregate/cqrs/eventstore" "github.com/plgd-dev/kit/v2/strings" @@ -29,7 +29,7 @@ func getDeviceIDFilter(queries []eventstore.DeleteQuery) bson.A { func (s *EventStore) Delete(ctx context.Context, queries []eventstore.DeleteQuery) error { deviceIDFilter := getDeviceIDFilter(queries) if len(deviceIDFilter) == 0 { - return fmt.Errorf("failed to delete documents: invalid query") + return errors.New("failed to delete documents: invalid query") } col := s.client().Database(s.DBName()).Collection(getEventCollectionName()) diff --git a/resource-aggregate/cqrs/eventstore/mongodb/delete_test.go b/resource-aggregate/cqrs/eventstore/mongodb/delete_test.go index 5aa075fa6..259c65511 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/delete_test.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/delete_test.go @@ -62,7 +62,7 @@ func TestEventStoreDelete(t *testing.T) { ctx := context.Background() store, err := NewTestEventStore(ctx, fileWatcher, logger) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, store) defer func() { t.Log("clearing db") diff --git a/resource-aggregate/cqrs/eventstore/mongodb/eventstore.go b/resource-aggregate/cqrs/eventstore/mongodb/eventstore.go index 78d5e8247..7d84b0c52 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/eventstore.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/eventstore.go @@ -49,6 +49,7 @@ const ( isActiveKey = "isactive" latestETagKey = "latestetag" etagKey = "etag" + typesKey = "types" latestETagKeyTimestampKey = latestETagKey + "." + timestampKey serviceIDKey = "serviceid" ) @@ -94,6 +95,12 @@ var groupIDETagLatestTimestampQueryIndex = bson.D{ {Key: latestETagKeyTimestampKey, Value: -1}, } +var groupIDTypesQueryIndex = bson.D{ + {Key: groupIDKey, Value: 1}, + {Key: typesKey, Value: 1}, + {Key: isActiveKey, Value: 1}, +} + type signOperator string const ( @@ -168,7 +175,7 @@ func newEventStoreWithClient(ctx context.Context, store *pkgMongo.Store, dbPrefi } if logDebugfFunc == nil { - logDebugfFunc = func(fmt string, args ...interface{}) { + logDebugfFunc = func(string, ...interface{}) { // no-op if not set } } @@ -206,6 +213,7 @@ func newEventStoreWithClient(ctx context.Context, store *pkgMongo.Store, dbPrefi aggregateIDLatestTimestampQueryIndex, groupIDETagLatestTimestampQueryIndex, serviceIDQueryIndex, + groupIDTypesQueryIndex, ) if err != nil { return nil, fmt.Errorf("cannot save events: %w", err) @@ -252,7 +260,7 @@ func getDocID(event eventstore.Event) string { } func getLatestSnapshotVersion(events []eventstore.Event) (uint64, error) { - err := fmt.Errorf("not found") + err := errors.New("not found") var latestSnapshotVersion uint64 for _, e := range events { if e.IsSnapshot() { @@ -290,7 +298,7 @@ func tryToSetServiceID(doc bson.M, events []eventstore.Event) bson.M { } func makeDBDoc(events []eventstore.Event, marshaler MarshalerFunc) (bson.M, error) { - etag, e, err := makeDBEventsAndGetETag(events, marshaler) + etag, types, e, err := makeDBEventsAndGetETag(events, marshaler) if err != nil { return nil, fmt.Errorf("cannot insert first events('%v'): %w", events, err) } @@ -313,6 +321,9 @@ func makeDBDoc(events []eventstore.Event, marshaler MarshalerFunc) (bson.M, erro if etag != nil { d[etagKey] = etag.ETag } + if len(types) > 0 { + d[typesKey] = types + } return tryToSetServiceID(d, events), nil } @@ -354,14 +365,15 @@ func (s *EventStore) Close(ctx context.Context) error { } // newDBEvent returns a new dbEvent for an eventstore. -func makeDBEventsAndGetETag(events []eventstore.Event, marshaler MarshalerFunc) (*eventstore.ETagData, []bson.M, error) { +func makeDBEventsAndGetETag(events []eventstore.Event, marshaler MarshalerFunc) (*eventstore.ETagData, []string, []bson.M, error) { dbEvents := make([]bson.M, 0, len(events)) var etag *eventstore.ETagData + var types []string for idx, event := range events { // Marshal event data if there is any. raw, err := marshaler(event) if err != nil { - return nil, nil, fmt.Errorf("cannot create db event from event[%v]: %w", idx, err) + return nil, nil, nil, fmt.Errorf("cannot create db event from event[%v]: %w", idx, err) } dbEvents = append(dbEvents, bson.M{ versionKey: event.Version(), @@ -374,6 +386,9 @@ func makeDBEventsAndGetETag(events []eventstore.Event, marshaler MarshalerFunc) if et != nil { etag = et } + if len(event.Types()) > 0 { + types = event.Types() + } } - return etag, dbEvents, nil + return etag, types, dbEvents, nil } diff --git a/resource-aggregate/cqrs/eventstore/mongodb/eventstore_test.go b/resource-aggregate/cqrs/eventstore/mongodb/eventstore_test.go index c556233be..2409bc29b 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/eventstore_test.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/eventstore_test.go @@ -44,7 +44,7 @@ func TestEventStore(t *testing.T) { ctx := context.Background() store, err := NewTestEventStore(ctx, fileWatcher, logger) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, store) defer func() { t.Log("clearing db") diff --git a/resource-aggregate/cqrs/eventstore/mongodb/getLatestDeviceETags.go b/resource-aggregate/cqrs/eventstore/mongodb/getLatestDeviceETags.go index decf83cb7..d8f3bcf98 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/getLatestDeviceETags.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/getLatestDeviceETags.go @@ -36,7 +36,7 @@ func decodeETag(cur *mongo.Cursor) ([]byte, error) { return nil, fmt.Errorf("cannot convert etag %T to primitive.Binary", etagRaw) } if len(etag.Data) == 0 { - return nil, fmt.Errorf("etag is empty") + return nil, errors.New("etag is empty") } return etag.Data, nil } @@ -49,7 +49,7 @@ func (s *EventStore) GetLatestDeviceETags(ctx context.Context, deviceID string, s.LogDebugfFunc("mongodb.Evenstore.GetLatestETag takes %v", time.Since(t)) }() if deviceID == "" { - return nil, fmt.Errorf("deviceID is invalid") + return nil, errors.New("deviceID is invalid") } filter := bson.D{ bson.E{Key: groupIDKey, Value: deviceID}, diff --git a/resource-aggregate/cqrs/eventstore/mongodb/getLatestDeviceETags_test.go b/resource-aggregate/cqrs/eventstore/mongodb/getLatestDeviceETags_test.go index 3847cf617..6cb6ed468 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/getLatestDeviceETags_test.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/getLatestDeviceETags_test.go @@ -23,7 +23,7 @@ func TestGetLatestDeviceETAG(t *testing.T) { ctx := context.Background() store, err := NewTestEventStore(ctx, fileWatcher, logger) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, store) defer func() { t.Log("clearing db") diff --git a/resource-aggregate/cqrs/eventstore/mongodb/getevents.go b/resource-aggregate/cqrs/eventstore/mongodb/getevents.go index 777ea40d1..f9a77bd4b 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/getevents.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/getevents.go @@ -2,7 +2,7 @@ package mongodb import ( "context" - "fmt" + "errors" "time" "github.com/hashicorp/go-multierror" @@ -107,7 +107,7 @@ func getEventsQueriesToMongoQuery(groupID string, queries []eventstore.GetEvents func (s *EventStore) getEvents(ctx context.Context, groupID string, queries []eventstore.GetEventsQuery, timestamp int64, eventHandler eventstore.Handler) error { filter, opts := getEventsQueriesToMongoQuery(groupID, queries, timestamp) - return s.loadEventsQuery(ctx, eventHandler, nil, filter, opts) + return s.loadEventsQuery(ctx, eventHandler, nil, []mongoQuery{{filter: filter, options: opts}}) } type ResourceIdFilter struct { @@ -163,7 +163,7 @@ func (s *EventStore) GetEvents(ctx context.Context, queries []eventstore.GetEven s.LogDebugfFunc("mongodb.Evenstore.GetEvents takes %v", time.Since(t)) }() if len(queries) == 0 { - return fmt.Errorf("not supported") + return errors.New("not supported") } eventFilter := GetNormalizedGetEventsFilter(queries) diff --git a/resource-aggregate/cqrs/eventstore/mongodb/getevents_test.go b/resource-aggregate/cqrs/eventstore/mongodb/getevents_test.go index d826e2cd6..3d093163b 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/getevents_test.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/getevents_test.go @@ -55,6 +55,10 @@ func getETag(deviceIndex int, resourceIndex int) []byte { return []byte("device" + strconv.Itoa(deviceIndex) + ".resource" + strconv.Itoa(resourceIndex)) } +func getTypes(resourceIndex int) []string { + return []string{"type" + strconv.Itoa(resourceIndex%3), "type" + strconv.Itoa((resourceIndex%3)+3)} +} + func getNLatestETag(deviceIndex int, limit int) [][]byte { if limit == 0 { limit = getEventsResourceCount / getEventsDeviceCount @@ -88,6 +92,7 @@ func addEventsForGetEventsToDB(ctx context.Context, t *testing.T, store *mongodb TimestampI: 1 + resourceTimestamp[resourceIndex], ETagI: getETag(deviceIndex, resourceIndex), ServiceIDI: getServiceID(serviceIndex), + TypesI: getTypes(resourceIndex), }) resourceVersion[resourceIndex]++ @@ -309,7 +314,7 @@ func Test_getNormalizedGetEventsFilter(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := mongodb.GetNormalizedGetEventsFilter(tt.args.queries) - require.Equal(t, got, tt.want) + require.Equal(t, tt.want, got) }) } } diff --git a/resource-aggregate/cqrs/eventstore/mongodb/load.go b/resource-aggregate/cqrs/eventstore/mongodb/load.go index 15a341678..3826c16b2 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/load.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/load.go @@ -52,7 +52,7 @@ func (i *iterator) parseDocument() bool { return false } if len(i.events) == 0 { - i.err = fmt.Errorf("invalid data, no events found") + i.err = errors.New("invalid data, no events found") return false } i.groupID, ok = doc[groupIDKey].(string) @@ -199,22 +199,29 @@ func (r *queryResolver) check(aggregateID string, version int64) bool { } // Create mongodb find query to load events -func (s *EventStore) loadEventsQuery(ctx context.Context, eh eventstore.Handler, queryResolver *queryResolver, filter interface{}, opts ...*options.FindOptions) error { +func (s *EventStore) loadEventsQuery(ctx context.Context, eh eventstore.Handler, queryResolver *queryResolver, queries []mongoQuery) error { col := s.client().Database(s.DBName()).Collection(getEventCollectionName()) - iter, err := col.Find(ctx, filter, opts...) - if errors.Is(err, mongo.ErrNilDocument) { - return nil - } - if err != nil { - return err - } - i := newIterator(iter, queryResolver, s.dataUnmarshaler, s.LogDebugfFunc) - err = eh.Handle(ctx, i) - errClose := iter.Close(ctx) - if err == nil { - return errClose + var errs *multierror.Error + for _, q := range queries { + iter, err := col.Find(ctx, q.filter, q.options) + if errors.Is(err, mongo.ErrNilDocument) { + continue + } + if err != nil { + errs = multierror.Append(errs, err) + continue + } + i := newIterator(iter, queryResolver, s.dataUnmarshaler, s.LogDebugfFunc) + err = eh.Handle(ctx, i) + if err != nil { + errs = multierror.Append(errs, err) + } + err = iter.Close(ctx) + if err != nil { + errs = multierror.Append(errs, err) + } } - return err + return errs.ErrorOrNil() } func (r *queryResolver) toMongoQuery(maxVersionKey string) (filter bson.M, hint bson.D) { @@ -288,10 +295,15 @@ func (s *EventStore) loadMongoQuery(ctx context.Context, eh eventstore.Handler, filter, hint := queryResolver.toMongoQuery(maxVersionKey) opts := options.Find() opts.SetHint(hint) - return s.loadEventsQuery(ctx, eh, queryResolver, filter, opts) + return s.loadEventsQuery(ctx, eh, queryResolver, []mongoQuery{{filter: filter, options: opts}}) +} + +type mongoQuery struct { + filter interface{} + options *options.FindOptions } -func snapshotQueriesToMongoQuery(groupID string, queries []eventstore.SnapshotQuery) (interface{}, *options.FindOptions) { +func snapshotQueriesToMongoQuery(groupID string, queries []eventstore.SnapshotQuery) []mongoQuery { opts := options.Find() opts.SetAllowDiskUse(true) opts.SetProjection(bson.M{ @@ -309,57 +321,183 @@ func snapshotQueriesToMongoQuery(groupID string, queries []eventstore.SnapshotQu }) if len(queries) == 0 { opts.SetHint(groupIDQueryIndex) - return bson.D{ - {Key: groupIDKey, Value: groupID}, {Key: isActiveKey, Value: true}, - }, opts + return []mongoQuery{ + { + filter: bson.D{ + {Key: groupIDKey, Value: groupID}, {Key: isActiveKey, Value: true}, + }, + options: opts, + }, + } } - opts.SetHint(groupIDaggregateIDQueryIndex) - orQueries := make([]bson.D, 0, 32) + optsTypes := options.Find() + // create a copy of the options + *optsTypes = *opts + resourceQueries := make([]bson.D, 0, 32) + typeQueries := make([]bson.D, 0, 32) for _, q := range queries { + if q.AggregateID == "" && len(q.Types) == 0 { + opts.SetHint(groupIDQueryIndex) + return []mongoQuery{ + { + filter: bson.D{ + {Key: groupIDKey, Value: groupID}, {Key: isActiveKey, Value: true}, + }, + options: opts, + }, + } + } + if q.AggregateID == "" && len(q.Types) > 0 { + optsTypes.SetHint(groupIDTypesQueryIndex) + typeQueries = append(typeQueries, bson.D{{Key: groupIDKey, Value: groupID}, {Key: typesKey, Value: bson.M{"$all": q.Types}}, {Key: isActiveKey, Value: true}}) + continue + } + if q.AggregateID != "" { - orQueries = append(orQueries, bson.D{{Key: groupIDKey, Value: groupID}, {Key: aggregateIDKey, Value: q.AggregateID}, {Key: isActiveKey, Value: true}}) + opts.SetHint(groupIDaggregateIDQueryIndex) + resourceQueries = append(resourceQueries, bson.D{{Key: groupIDKey, Value: groupID}, {Key: aggregateIDKey, Value: q.AggregateID}, {Key: isActiveKey, Value: true}}) } } - return bson.M{ - "$or": orQueries, - }, opts + + r := make([]mongoQuery, 0, 2) + if len(resourceQueries) > 0 { + r = append(r, mongoQuery{ + filter: bson.M{"$or": resourceQueries}, + options: opts, + }) + } + if len(typeQueries) > 0 { + r = append(r, mongoQuery{ + filter: bson.M{"$or": typeQueries}, + options: optsTypes, + }) + } + return r } func (s *EventStore) loadFromSnapshot(ctx context.Context, groupID string, queries []eventstore.SnapshotQuery, eventHandler eventstore.Handler) error { - filter, opts := snapshotQueriesToMongoQuery(groupID, queries) - return s.loadEventsQuery(ctx, eventHandler, nil, filter, opts) + mongoQueries := snapshotQueriesToMongoQuery(groupID, queries) + if len(mongoQueries) > 1 { + return errors.New("too many types of queries") + } + return s.loadEventsQuery(ctx, eventHandler, nil, mongoQueries) } -// LoadFromSnapshot loads events from the last snapshot eventstore. -func (s *EventStore) LoadFromSnapshot(ctx context.Context, queries []eventstore.SnapshotQuery, eventHandler eventstore.Handler) error { - s.LogDebugfFunc("mongodb.Evenstore.LoadFromSnapshot start") - t := time.Now() - defer func() { - s.LogDebugfFunc("mongodb.Evenstore.LoadFromSnapshot takes %v", time.Since(t)) - }() - if len(queries) == 0 { - return fmt.Errorf("not supported") +func resourceTypesIsSubset(slice, subset []string) bool { + if len(slice) == 0 { + return false + } + if len(slice) > len(subset) { + return false + } + set := make(map[string]struct{}, len(slice)) + for _, s := range slice { + set[s] = struct{}{} + } + for _, s := range subset { + delete(set, s) + if len(set) == 0 { + return true + } + } + return false +} + +func uniqueQueryWithEmptyAggregateID(queries []eventstore.SnapshotQuery, query eventstore.SnapshotQuery) []eventstore.SnapshotQuery { + if len(query.Types) == 0 { + // get all events without filter + return []eventstore.SnapshotQuery{query} + } + for idx, q := range queries { + if resourceTypesIsSubset(query.Types, q.Types) { + // get all events with the certain type, replace the queries with the more or equal general one + queries[idx] = query + queries = removeDuplicates(queries, idx, func(qa eventstore.SnapshotQuery) bool { return resourceTypesIsSubset(query.Types, qa.Types) }) + return queries + } + } + return append(queries, query) +} + +func uniqueQueryHandleAtIndex(queries []eventstore.SnapshotQuery, query eventstore.SnapshotQuery, idx int) ([]eventstore.SnapshotQuery, bool) { + q := queries[idx] + if q.AggregateID == "" && len(q.Types) == 0 || resourceTypesIsSubset(q.Types, query.Types) { + return queries, true // No need to add more specific one if there's a general query + } + + if q.AggregateID == query.AggregateID { + if len(query.Types) == 0 { + queries[idx] = query + queries = removeDuplicates(queries, idx, func(qa eventstore.SnapshotQuery) bool { return qa.AggregateID == query.AggregateID }) + return queries, true + } + if len(q.Types) == 0 || resourceTypesIsSubset(q.Types, query.Types) { + return queries, true // No need to add more general one if there's a more specific query + } + if resourceTypesIsSubset(query.Types, q.Types) { + // replace query with the more general one + queries[idx] = query + queries = removeDuplicates(queries, idx, func(qa eventstore.SnapshotQuery) bool { return resourceTypesIsSubset(qa.Types, query.Types) }) + return queries, true + } + } + return queries, false +} + +func uniqueQuery(queries []eventstore.SnapshotQuery, query eventstore.SnapshotQuery) []eventstore.SnapshotQuery { + if query.AggregateID == "" { + return uniqueQueryWithEmptyAggregateID(queries, query) + } + + for idx := range queries { + newQueries, handled := uniqueQueryHandleAtIndex(queries, query, idx) + if handled { + return newQueries + } } - normalizeQuery := make(map[string][]eventstore.SnapshotQuery) + return append(queries, query) +} + +func removeDuplicates(queries []eventstore.SnapshotQuery, startIdx int, remove func(q eventstore.SnapshotQuery) bool) []eventstore.SnapshotQuery { + for i := startIdx + 1; i < len(queries); i++ { + if remove(queries[i]) { + queries = append(queries[:i], queries[i+1:]...) + i-- + } + } + return queries +} + +func normalizeSnapshotQuery(queries []eventstore.SnapshotQuery) map[string][]eventstore.SnapshotQuery { + normalizedQuery := make(map[string][]eventstore.SnapshotQuery, len(queries)) + // split queries by groupID for _, query := range queries { if query.GroupID == "" { continue } - if query.AggregateID == "" { - normalizeQuery[query.GroupID] = make([]eventstore.SnapshotQuery, 0, 1) - continue - } - v, ok := normalizeQuery[query.GroupID] + v, ok := normalizedQuery[query.GroupID] if !ok { v = make([]eventstore.SnapshotQuery, 0, 4) - } else if len(v) == 0 { - continue } - v = append(v, query) - normalizeQuery[query.GroupID] = v + normalizedQuery[query.GroupID] = uniqueQuery(v, query) } + return normalizedQuery +} + +// LoadFromSnapshot loads events from the last snapshot eventstore. +func (s *EventStore) LoadFromSnapshot(ctx context.Context, queries []eventstore.SnapshotQuery, eventHandler eventstore.Handler) error { + s.LogDebugfFunc("mongodb.Evenstore.LoadFromSnapshot start") + t := time.Now() + defer func() { + s.LogDebugfFunc("mongodb.Evenstore.LoadFromSnapshot takes %v", time.Since(t)) + }() + if len(queries) == 0 { + return errors.New("not supported") + } + + normalizeQuery := normalizeSnapshotQuery(queries) var errors *multierror.Error for groupID, queries := range normalizeQuery { diff --git a/resource-aggregate/cqrs/eventstore/mongodb/loadDeviceMetadataByServiceIDs.go b/resource-aggregate/cqrs/eventstore/mongodb/loadDeviceMetadataByServiceIDs.go index 331b0811d..03a613c25 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/loadDeviceMetadataByServiceIDs.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/loadDeviceMetadataByServiceIDs.go @@ -20,7 +20,7 @@ func (s *EventStore) LoadDeviceMetadataByServiceIDs(ctx context.Context, service s.LogDebugfFunc("mongodb.Evenstore.LoadDocMetadataFromByServiceIDs takes %v", time.Since(t)) }() if len(serviceIDs) == 0 { - return nil, fmt.Errorf("not supported") + return nil, errors.New("not supported") } serviceIDs = strings.Unique(serviceIDs) diff --git a/resource-aggregate/cqrs/eventstore/mongodb/loadDeviceMetadataByServiceIDs_test.go b/resource-aggregate/cqrs/eventstore/mongodb/loadDeviceMetadataByServiceIDs_test.go index 2cda0511d..cf865b675 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/loadDeviceMetadataByServiceIDs_test.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/loadDeviceMetadataByServiceIDs_test.go @@ -23,7 +23,7 @@ func TestLoadDeviceMetadataByServiceIDs(t *testing.T) { ctx := context.Background() store, err := NewTestEventStore(ctx, fileWatcher, logger) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, store) defer func() { t.Log("clearing db") diff --git a/resource-aggregate/cqrs/eventstore/mongodb/load_internal_test.go b/resource-aggregate/cqrs/eventstore/mongodb/load_internal_test.go new file mode 100644 index 000000000..e91bf1ece --- /dev/null +++ b/resource-aggregate/cqrs/eventstore/mongodb/load_internal_test.go @@ -0,0 +1,163 @@ +package mongodb + +import ( + "testing" + + "github.com/plgd-dev/hub/v2/resource-aggregate/cqrs/eventstore" + "github.com/stretchr/testify/require" +) + +func TestUniqueQuery(t *testing.T) { + type args struct { + queries []eventstore.SnapshotQuery + query eventstore.SnapshotQuery + } + test := []struct { + name string + args args + want []eventstore.SnapshotQuery + }{ + { + name: "first query", + args: args{ + queries: nil, + query: eventstore.SnapshotQuery{AggregateID: "1", Types: []string{"type1"}}, + }, + want: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + }, + }, + { + name: "same query", + args: args{ + queries: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + }, + query: eventstore.SnapshotQuery{AggregateID: "1", Types: []string{"type1"}}, + }, + want: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + }, + }, + { + name: "two queries", + args: args{ + queries: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + }, + query: eventstore.SnapshotQuery{Types: []string{"type2"}}, + }, + want: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + {Types: []string{"type2"}}, + }, + }, + { + name: "most general query", + args: args{ + queries: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + }, + query: eventstore.SnapshotQuery{}, + }, + want: []eventstore.SnapshotQuery{ + {}, + }, + }, + { + name: "replace a query with more general query", + args: args{ + queries: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + {AggregateID: "1", Types: []string{"type2"}}, + {AggregateID: "2", Types: []string{"type2"}}, + }, + query: eventstore.SnapshotQuery{Types: []string{"type2"}}, + }, + want: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + {Types: []string{"type2"}}, + }, + }, + { + name: "replace more queries with more general query with the aggregateID", + args: args{ + queries: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + {AggregateID: "1", Types: []string{"type2"}}, + }, + query: eventstore.SnapshotQuery{AggregateID: "1"}, + }, + want: []eventstore.SnapshotQuery{ + {AggregateID: "1"}, + }, + }, + { + name: "replace a query with more general query with the aggregateID", + args: args{ + queries: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type2", "type1"}}, + }, + query: eventstore.SnapshotQuery{AggregateID: "1", Types: []string{"type1"}}, + }, + want: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + }, + }, + { + name: "use general query instead of more specific query with the aggregateID", + args: args{ + queries: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + }, + query: eventstore.SnapshotQuery{AggregateID: "1", Types: []string{"type1", "type2"}}, + }, + want: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1"}}, + }, + }, + { + name: "use general query instead of more specific query with multiple type and the aggregateID ", + args: args{ + queries: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1", "type2", "type3"}}, + }, + query: eventstore.SnapshotQuery{AggregateID: "1", Types: []string{"type1", "type3"}}, + }, + want: []eventstore.SnapshotQuery{ + {AggregateID: "1", Types: []string{"type1", "type3"}}, + }, + }, + { + name: "use general query instead of more specific query", + args: args{ + queries: []eventstore.SnapshotQuery{ + {Types: []string{"type1"}}, + }, + query: eventstore.SnapshotQuery{AggregateID: "1", Types: []string{"type1", "type2"}}, + }, + want: []eventstore.SnapshotQuery{ + {Types: []string{"type1"}}, + }, + }, + { + name: "general and specific query with types", + args: args{ + queries: []eventstore.SnapshotQuery{ + {Types: []string{"type2", "type1"}}, + }, + query: eventstore.SnapshotQuery{AggregateID: "1", Types: []string{"type1"}}, + }, + want: []eventstore.SnapshotQuery{ + {Types: []string{"type2", "type1"}}, + {AggregateID: "1", Types: []string{"type1"}}, + }, + }, + } + for _, tt := range test { + t.Run(tt.name, func(t *testing.T) { + got := uniqueQuery(tt.args.queries, tt.args.query) + require.Equal(t, tt.want, got) + }) + } +} diff --git a/resource-aggregate/cqrs/eventstore/mongodb/load_test.go b/resource-aggregate/cqrs/eventstore/mongodb/load_test.go new file mode 100644 index 000000000..3f6c376f5 --- /dev/null +++ b/resource-aggregate/cqrs/eventstore/mongodb/load_test.go @@ -0,0 +1,126 @@ +package mongodb_test + +import ( + "context" + "testing" + + "github.com/plgd-dev/hub/v2/pkg/fsnotify" + "github.com/plgd-dev/hub/v2/pkg/log" + "github.com/plgd-dev/hub/v2/resource-aggregate/cqrs/eventstore" + "github.com/stretchr/testify/require" +) + +func TestLoadFromSnapshot(t *testing.T) { + type args struct { + queries []eventstore.SnapshotQuery + } + type device struct { + ID string + NumResources int + } + tests := []struct { + name string + args args + want []device + wantErr bool + }{ + { + name: "All group events", + args: args{ + queries: []eventstore.SnapshotQuery{ + { + GroupID: getDeviceID(0), + }, + }, + }, + want: []device{ + { + ID: getDeviceID(0), + NumResources: 20, + }, + }, + }, + { + name: "Group events with aggregateID", + args: args{ + queries: []eventstore.SnapshotQuery{ + { + GroupID: getDeviceID(0), + AggregateID: getAggregateID(0), + }, + }, + }, + want: []device{ + { + ID: getDeviceID(0), + NumResources: 1, + }, + }, + }, + { + name: "Group events with type filter", + args: args{ + queries: []eventstore.SnapshotQuery{ + { + GroupID: getDeviceID(0), + Types: getTypes(0), + }, + { + GroupID: getDeviceID(1), + Types: getTypes(3)[0:1], + }, + }, + }, + want: []device{ + { + ID: getDeviceID(0), + NumResources: 7, + }, + { + ID: getDeviceID(1), + NumResources: 6, + }, + }, + }, + } + logger := log.NewLogger(log.MakeDefaultConfig()) + fileWatcher, err := fsnotify.NewWatcher(logger) + require.NoError(t, err) + defer func() { + errC := fileWatcher.Close() + require.NoError(t, errC) + }() + + ctx := context.Background() + store, err := NewTestEventStore(ctx, fileWatcher, logger) + require.NoError(t, err) + require.NotNil(t, store) + defer func() { + t.Log("clearing db") + err = store.Clear(ctx) + require.NoError(t, err) + err := store.Close(ctx) + require.NoError(t, err) + }() + + _ = addEventsForGetEventsToDB(ctx, t, store) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := NewMockEventHandler() + err := store.LoadFromSnapshot(ctx, tt.args.queries, h) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + events := h.PopEvents() + require.Len(t, events, len(tt.want)) + for _, want := range tt.want { + ags, ok := events[want.ID] + require.True(t, ok) + require.Len(t, ags, want.NumResources) + } + }) + } +} diff --git a/resource-aggregate/cqrs/eventstore/mongodb/maintenance_test.go b/resource-aggregate/cqrs/eventstore/mongodb/maintenance_test.go index 8acf362f3..7aa5ea00d 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/maintenance_test.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/maintenance_test.go @@ -75,7 +75,7 @@ func TestMaintenance(t *testing.T) { mongodb.WithMarshaler(bson.Marshal), mongodb.WithUnmarshaler(bson.Unmarshal), ) - assert.NoError(t, err) + require.NoError(t, err) assert.NotNil(t, store) defer func() { t.Log("clearing db") @@ -161,5 +161,5 @@ func TestMaintenance(t *testing.T) { eh3 := newMockRecordHandler() err = store.Query(ctx, 777, eh3) require.NoError(t, err) - require.Equal(t, 0, len(eh3.tasks)) + require.Empty(t, eh3.tasks) } diff --git a/resource-aggregate/cqrs/eventstore/mongodb/save.go b/resource-aggregate/cqrs/eventstore/mongodb/save.go index 2e3978574..a95f1f192 100644 --- a/resource-aggregate/cqrs/eventstore/mongodb/save.go +++ b/resource-aggregate/cqrs/eventstore/mongodb/save.go @@ -39,7 +39,7 @@ func IsDup(err error) bool { } func (s *EventStore) saveEvent(ctx context.Context, col *mongo.Collection, events []eventstore.Event) (status eventstore.SaveStatus, err error) { - etag, e, err := makeDBEventsAndGetETag(events, s.dataMarshaler) + etag, types, e, err := makeDBEventsAndGetETag(events, s.dataMarshaler) if err != nil { return eventstore.Fail, err } @@ -57,6 +57,9 @@ func (s *EventStore) saveEvent(ctx context.Context, col *mongo.Collection, event updateSet[latestETagKey] = makeDBETag(etag) } tryToSetServiceID(updateSet, events) + if len(types) > 0 { + updateSet[typesKey] = types + } // find document of aggregate with previous version // latestVersion shall be lower by 1 as new event otherwise other event was stored (occ). diff --git a/resource-aggregate/cqrs/eventstore/projection.go b/resource-aggregate/cqrs/eventstore/projection.go index 5f7d8ed58..505f1f4bc 100644 --- a/resource-aggregate/cqrs/eventstore/projection.go +++ b/resource-aggregate/cqrs/eventstore/projection.go @@ -71,7 +71,7 @@ type Projection struct { // NewProjection projection over eventstore. func NewProjection(store EventStore, factoryModel FactoryModelFunc, logDebugfFunc LogDebugfFunc) *Projection { if logDebugfFunc == nil { - logDebugfFunc = func(fmt string, args ...interface{}) {} + logDebugfFunc = func(string, ...interface{}) {} } return &Projection{ store: store, @@ -97,7 +97,7 @@ func (i *iterator) RewindToNextAggregateEvent(ctx context.Context) EventUnmarsha if nextAggregateEvent != nil { return nextAggregateEvent } - if snapshot == nil && nextAggregateEvent == nil { + if snapshot == nil { return nil } } @@ -137,37 +137,37 @@ func (i *iterator) RewindIgnore(ctx context.Context) (EventUnmarshaler, bool) { } func (i *iterator) Next(ctx context.Context) (EventUnmarshaler, bool) { - if i.firstEvent != nil { - tmp := i.firstEvent - i.firstEvent = nil - ignore, reload := i.model.Update(tmp) - i.model.LogDebugfFunc("projection.iterator.next: GroupID %v: AggregateID %v: Version %v, EvenType %v, ignore %v reload %v", tmp.GroupID, tmp.AggregateID, tmp.Version, tmp.EventType, ignore, reload) - if reload { - snapshot, nextAggregateEvent := i.RewindToSnapshot(ctx) - if snapshot == nil { - i.nextEventToProcess = nextAggregateEvent - i.reload = &VersionQuery{GroupID: tmp.GroupID(), AggregateID: tmp.AggregateID(), Version: i.model.version} - return nil, false - } - tmp = snapshot - ignore, reload = i.model.Update(tmp) - if reload { - i.nextEventToProcess = i.RewindToNextAggregateEvent(ctx) - i.reload = &VersionQuery{GroupID: tmp.GroupID(), AggregateID: tmp.AggregateID(), Version: i.model.version} - return nil, false - } - } - if ignore { - return i.RewindIgnore(ctx) + if i.firstEvent == nil { + e, ok := i.RewindIgnore(ctx) + if ok { + i.model.LogDebugfFunc("projection.iterator.next: GroupID %v: AggregateID %v: Version %v, EvenType %v", e.GroupID, e.AggregateID, e.Version, e.EventType) } - return tmp, true + return e, ok } - e, ok := i.RewindIgnore(ctx) - if ok { - i.model.LogDebugfFunc("projection.iterator.next: GroupID %v: AggregateID %v: Version %v, EvenType %v", e.GroupID, e.AggregateID, e.Version, e.EventType) + tmp := i.firstEvent + i.firstEvent = nil + ignore, reload := i.model.Update(tmp) + i.model.LogDebugfFunc("projection.iterator.next: GroupID %v: AggregateID %v: Version %v, EvenType %v, ignore %v reload %v", tmp.GroupID, tmp.AggregateID, tmp.Version, tmp.EventType, ignore, reload) + if reload { + snapshot, nextAggregateEvent := i.RewindToSnapshot(ctx) + if snapshot == nil { + i.nextEventToProcess = nextAggregateEvent + i.reload = &VersionQuery{GroupID: tmp.GroupID(), AggregateID: tmp.AggregateID(), Version: i.model.version} + return nil, false + } + tmp = snapshot + ignore, reload = i.model.Update(tmp) + if reload { + i.nextEventToProcess = i.RewindToNextAggregateEvent(ctx) + i.reload = &VersionQuery{GroupID: tmp.GroupID(), AggregateID: tmp.AggregateID(), Version: i.model.version} + return nil, false + } + } + if ignore { + return i.RewindIgnore(ctx) } - return e, ok + return tmp, true } func (i *iterator) Err() error { diff --git a/resource-aggregate/cqrs/eventstore/test/acceptance_testing.go b/resource-aggregate/cqrs/eventstore/test/acceptance_testing.go index 072764543..ddc1fdafe 100644 --- a/resource-aggregate/cqrs/eventstore/test/acceptance_testing.go +++ b/resource-aggregate/cqrs/eventstore/test/acceptance_testing.go @@ -287,7 +287,7 @@ func AcceptanceTest(ctx context.Context, t *testing.T, store eventstore.EventSto eh1 := NewMockEventHandler() err = store.LoadFromSnapshot(ctx, []eventstore.SnapshotQuery{{GroupID: uuid.Nil.String()}}, eh1) require.NoError(t, err) - require.Equal(t, 0, len(eh1.events)) + require.Empty(t, eh1.events) t.Log("load events") eh2 := NewMockEventHandler() diff --git a/resource-aggregate/cqrs/eventstore/test/events.go b/resource-aggregate/cqrs/eventstore/test/events.go index 126df9e2f..95747c70d 100644 --- a/resource-aggregate/cqrs/eventstore/test/events.go +++ b/resource-aggregate/cqrs/eventstore/test/events.go @@ -3,7 +3,6 @@ package test import ( "context" "errors" - "fmt" "reflect" "sort" "sync" @@ -20,7 +19,7 @@ var ( UserId: "userId", } - errCannotUnmarshalEvent = fmt.Errorf("cannot unmarshal event") + errCannotUnmarshalEvent = errors.New("cannot unmarshal event") ) func MakeResourceLinksPublishedEvent(resources []*commands.Resource, deviceID string, eventMetadata *events.EventMetadata) eventstore.EventUnmarshaler { @@ -101,24 +100,23 @@ func MakeAuditContext(userID string, correlationID string) *commands.AuditContex } } -func MakeResourceUpdatePending(resourceID *commands.ResourceId, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, validUntil time.Time) eventstore.EventUnmarshaler { - e := events.ResourceUpdatePending{ - ResourceId: resourceID, - Content: content, - AuditContext: auditContext, - EventMetadata: eventMetadata, - ValidUntil: pkgTime.UnixNano(validUntil), - } +func newResourceEvent[T interface { + GetResourceId() *commands.ResourceId + EventType() string + CopyData(e T) + GetEventMetadata() *events.EventMetadata + IsSnapshot() bool +}](e T) eventstore.EventUnmarshaler { return eventstore.NewLoadedEvent( e.GetEventMetadata().GetVersion(), - (&events.ResourceUpdatePending{}).EventType(), + e.EventType(), e.GetResourceId().ToUUID().String(), e.GetResourceId().GetDeviceId(), - false, + e.IsSnapshot(), time.Unix(0, e.GetEventMetadata().GetTimestamp()), func(v interface{}) error { - if x, ok := v.(*events.ResourceUpdatePending); ok { - x.CopyData(&e) + if x, ok := v.(T); ok { + x.CopyData(e) return nil } return errCannotUnmarshalEvent @@ -126,226 +124,121 @@ func MakeResourceUpdatePending(resourceID *commands.ResourceId, content *command ) } -func MakeResourceUpdated(resourceID *commands.ResourceId, status commands.Status, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext) eventstore.EventUnmarshaler { +func MakeResourceUpdatePending(resourceID *commands.ResourceId, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, validUntil time.Time, resourceTypes []string) eventstore.EventUnmarshaler { + e := events.ResourceUpdatePending{ + ResourceId: resourceID, + Content: content, + AuditContext: auditContext, + EventMetadata: eventMetadata, + ValidUntil: pkgTime.UnixNano(validUntil), + ResourceTypes: resourceTypes, + } + return newResourceEvent(&e) +} + +func MakeResourceUpdated(resourceID *commands.ResourceId, status commands.Status, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, resourceTypes []string) eventstore.EventUnmarshaler { e := events.ResourceUpdated{ ResourceId: resourceID, Content: content, Status: status, AuditContext: auditContext, EventMetadata: eventMetadata, + ResourceTypes: resourceTypes, } - return eventstore.NewLoadedEvent( - e.GetEventMetadata().GetVersion(), - (&events.ResourceUpdated{}).EventType(), - e.GetResourceId().ToUUID().String(), - e.GetResourceId().GetDeviceId(), - false, - time.Unix(0, e.GetEventMetadata().GetTimestamp()), - func(v interface{}) error { - if x, ok := v.(*events.ResourceUpdated); ok { - x.CopyData(&e) - return nil - } - return errCannotUnmarshalEvent - }, - ) + return newResourceEvent(&e) } -func MakeResourceCreatePending(resourceID *commands.ResourceId, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, validUntil time.Time) eventstore.EventUnmarshaler { +func MakeResourceCreatePending(resourceID *commands.ResourceId, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, validUntil time.Time, resourceTypes []string) eventstore.EventUnmarshaler { e := events.ResourceCreatePending{ ResourceId: resourceID, Content: content, AuditContext: auditContext, EventMetadata: eventMetadata, ValidUntil: pkgTime.UnixNano(validUntil), + ResourceTypes: resourceTypes, } - return eventstore.NewLoadedEvent( - e.GetEventMetadata().GetVersion(), - (&events.ResourceCreatePending{}).EventType(), - e.GetResourceId().ToUUID().String(), - e.GetResourceId().GetDeviceId(), - false, - time.Unix(0, e.GetEventMetadata().GetTimestamp()), - func(v interface{}) error { - if x, ok := v.(*events.ResourceCreatePending); ok { - x.CopyData(&e) - return nil - } - return errCannotUnmarshalEvent - }, - ) + return newResourceEvent(&e) } -func MakeResourceCreated(resourceID *commands.ResourceId, status commands.Status, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext) eventstore.EventUnmarshaler { +func MakeResourceCreated(resourceID *commands.ResourceId, status commands.Status, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, resourceTypes []string) eventstore.EventUnmarshaler { e := events.ResourceCreated{ ResourceId: resourceID, Content: content, Status: status, AuditContext: auditContext, EventMetadata: eventMetadata, + ResourceTypes: resourceTypes, } - return eventstore.NewLoadedEvent( - e.GetEventMetadata().GetVersion(), - (&events.ResourceCreated{}).EventType(), - e.GetResourceId().ToUUID().String(), - e.GetResourceId().GetDeviceId(), - false, - time.Unix(0, e.GetEventMetadata().GetTimestamp()), - func(v interface{}) error { - if x, ok := v.(*events.ResourceCreated); ok { - x.CopyData(&e) - return nil - } - return errCannotUnmarshalEvent - }, - ) + return newResourceEvent(&e) } -func MakeResourceChangedEvent(resourceID *commands.ResourceId, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext) eventstore.EventUnmarshaler { +func MakeResourceChangedEvent(resourceID *commands.ResourceId, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, resourceTypes []string) eventstore.EventUnmarshaler { e := events.ResourceChanged{ ResourceId: resourceID, AuditContext: auditContext, Content: content, EventMetadata: eventMetadata, + ResourceTypes: resourceTypes, } - return eventstore.NewLoadedEvent( - e.GetEventMetadata().GetVersion(), - (&events.ResourceChanged{}).EventType(), - e.GetResourceId().ToUUID().String(), - e.GetResourceId().GetDeviceId(), - false, - time.Unix(0, e.GetEventMetadata().GetTimestamp()), - func(v interface{}) error { - if x, ok := v.(*events.ResourceChanged); ok { - x.CopyData(&e) - return nil - } - return errCannotUnmarshalEvent - }, - ) + return newResourceEvent(&e) } -func MakeResourceRetrievePending(resourceID *commands.ResourceId, resourceInterface string, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, validUntil time.Time) eventstore.EventUnmarshaler { +func MakeResourceRetrievePending(resourceID *commands.ResourceId, resourceInterface string, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, validUntil time.Time, resourceTypes []string) eventstore.EventUnmarshaler { e := events.ResourceRetrievePending{ ResourceId: resourceID, ResourceInterface: resourceInterface, AuditContext: auditContext, EventMetadata: eventMetadata, ValidUntil: pkgTime.UnixNano(validUntil), + ResourceTypes: resourceTypes, } - return eventstore.NewLoadedEvent( - e.GetEventMetadata().GetVersion(), - (&events.ResourceRetrievePending{}).EventType(), - e.GetResourceId().ToUUID().String(), - e.GetResourceId().GetDeviceId(), - false, - time.Unix(0, e.GetEventMetadata().GetTimestamp()), - func(v interface{}) error { - if x, ok := v.(*events.ResourceRetrievePending); ok { - x.CopyData(&e) - return nil - } - return errCannotUnmarshalEvent - }, - ) + return newResourceEvent(&e) } -func MakeResourceRetrieved(resourceID *commands.ResourceId, status commands.Status, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext) eventstore.EventUnmarshaler { +func MakeResourceRetrieved(resourceID *commands.ResourceId, status commands.Status, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, resourceTypes []string) eventstore.EventUnmarshaler { e := events.ResourceRetrieved{ ResourceId: resourceID, Content: content, Status: status, AuditContext: auditContext, EventMetadata: eventMetadata, + ResourceTypes: resourceTypes, } - return eventstore.NewLoadedEvent( - e.GetEventMetadata().GetVersion(), - (&events.ResourceRetrieved{}).EventType(), - e.GetResourceId().ToUUID().String(), - e.GetResourceId().GetDeviceId(), - false, - time.Unix(0, e.GetEventMetadata().GetTimestamp()), - func(v interface{}) error { - if x, ok := v.(*events.ResourceRetrieved); ok { - x.CopyData(&e) - return nil - } - return errCannotUnmarshalEvent - }, - ) + return newResourceEvent(&e) } -func MakeResourceDeletePending(resourceID *commands.ResourceId, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, validUntil time.Time) eventstore.EventUnmarshaler { +func MakeResourceDeletePending(resourceID *commands.ResourceId, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, validUntil time.Time, resourceTypes []string) eventstore.EventUnmarshaler { e := events.ResourceDeletePending{ ResourceId: resourceID, AuditContext: auditContext, EventMetadata: eventMetadata, ValidUntil: pkgTime.UnixNano(validUntil), + ResourceTypes: resourceTypes, } - return eventstore.NewLoadedEvent( - e.GetEventMetadata().GetVersion(), - (&events.ResourceDeletePending{}).EventType(), - e.GetResourceId().ToUUID().String(), - e.GetResourceId().GetDeviceId(), - false, - time.Unix(0, e.GetEventMetadata().GetTimestamp()), - func(v interface{}) error { - if x, ok := v.(*events.ResourceDeletePending); ok { - x.CopyData(&e) - return nil - } - return errCannotUnmarshalEvent - }, - ) + return newResourceEvent(&e) } -func MakeResourceDeleted(resourceID *commands.ResourceId, status commands.Status, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext) eventstore.EventUnmarshaler { +func MakeResourceDeleted(resourceID *commands.ResourceId, status commands.Status, content *commands.Content, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, resourceTypes []string) eventstore.EventUnmarshaler { e := events.ResourceDeleted{ ResourceId: resourceID, Content: content, Status: status, AuditContext: auditContext, EventMetadata: eventMetadata, + ResourceTypes: resourceTypes, } - return eventstore.NewLoadedEvent( - e.GetEventMetadata().GetVersion(), - (&events.ResourceDeleted{}).EventType(), - e.GetResourceId().ToUUID().String(), - e.GetResourceId().GetDeviceId(), - false, - time.Unix(0, e.GetEventMetadata().GetTimestamp()), - func(v interface{}) error { - if x, ok := v.(*events.ResourceDeleted); ok { - x.CopyData(&e) - return nil - } - return errCannotUnmarshalEvent - }, - ) + return newResourceEvent(&e) } -func MakeResourceStateSnapshotTaken(resourceID *commands.ResourceId, latestResourceChange *events.ResourceChanged, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext) eventstore.EventUnmarshaler { +func MakeResourceStateSnapshotTaken(resourceID *commands.ResourceId, latestResourceChange *events.ResourceChanged, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, resourceTypes []string) eventstore.EventUnmarshaler { e := events.NewResourceStateSnapshotTaken() e.ResourceId = resourceID e.LatestResourceChange = latestResourceChange e.EventMetadata = eventMetadata e.AuditContext = auditContext + e.ResourceTypes = resourceTypes - return eventstore.NewLoadedEvent( - e.GetEventMetadata().GetVersion(), - (&events.ResourceStateSnapshotTaken{}).EventType(), - e.GetResourceId().ToUUID().String(), - e.GetResourceId().GetDeviceId(), - true, - time.Unix(0, e.GetEventMetadata().GetTimestamp()), - func(v interface{}) error { - if x, ok := v.(*events.ResourceStateSnapshotTaken); ok { - x.CopyData(e) - return nil - } - return errCannotUnmarshalEvent - }, - ) + return newResourceEvent(e) } func MakeDeviceMetadataUpdatePending(deviceID string, twinEnabled *events.DeviceMetadataUpdatePending_TwinEnabled, eventMetadata *events.EventMetadata, auditContext *commands.AuditContext, validUntil time.Time) eventstore.EventUnmarshaler { @@ -423,15 +316,16 @@ func MakeDeviceMetadata(deviceID string, deviceMetadataUpdated *events.DeviceMet } type MockEvent struct { - VersionI uint64 `bson:"version"` - EventTypeI string `bson:"eventtype"` - IsSnapshotI bool `bson:"issnapshot"` - AggregateIDI string `bson:"aggregateid"` - GroupIDI string `bson:"groupid"` - DataI []byte `bson:"data"` - TimestampI int64 `bson:"timestamp"` - ETagI []byte `bson:"etag"` - ServiceIDI string `bson:"serviceid"` + VersionI uint64 `bson:"version"` + EventTypeI string `bson:"eventtype"` + IsSnapshotI bool `bson:"issnapshot"` + AggregateIDI string `bson:"aggregateid"` + GroupIDI string `bson:"groupid"` + DataI []byte `bson:"data"` + TimestampI int64 `bson:"timestamp"` + ETagI []byte `bson:"etag"` + ServiceIDI string `bson:"serviceid"` + TypesI []string `bson:"resourcetypes"` } func (e MockEvent) Version() uint64 { @@ -472,6 +366,10 @@ func (e MockEvent) ServiceID() (string, bool) { return e.ServiceIDI, true } +func (e MockEvent) Types() []string { + return e.TypesI +} + type MockEventHandler struct { lock sync.Mutex events map[string]map[string][]eventstore.Event diff --git a/resource-aggregate/cqrs/eventstore/test/eventstore.go b/resource-aggregate/cqrs/eventstore/test/eventstore.go index 3148c449b..54dcc707a 100644 --- a/resource-aggregate/cqrs/eventstore/test/eventstore.go +++ b/resource-aggregate/cqrs/eventstore/test/eventstore.go @@ -3,7 +3,6 @@ package test import ( "context" "errors" - "fmt" "github.com/plgd-dev/hub/v2/resource-aggregate/cqrs/eventstore" ) @@ -132,7 +131,7 @@ func (s *MockEventStore) LoadFromSnapshot(ctx context.Context, queries []eventst ret = append(ret, q) } if len(ret) == 0 { - return fmt.Errorf("cannot load events: not found") + return errors.New("cannot load events: not found") } return s.LoadFromVersion(ctx, ret, eventHandler) diff --git a/resource-aggregate/cqrs/projection/projection.go b/resource-aggregate/cqrs/projection/projection.go index a888d820d..e1ce3361b 100644 --- a/resource-aggregate/cqrs/projection/projection.go +++ b/resource-aggregate/cqrs/projection/projection.go @@ -24,7 +24,7 @@ type Projection struct { // NewProjection creates new resource projection. func NewProjection(ctx context.Context, name string, store eventstore.EventStore, subscriber eventbus.Subscriber, factoryModel eventstore.FactoryModelFunc) (*Projection, error) { - cqrsProjection, err := newProjection(ctx, store, name, subscriber, factoryModel, func(template string, args ...interface{}) {}) + cqrsProjection, err := newProjection(ctx, store, name, subscriber, factoryModel, func(string, ...interface{}) {}) if err != nil { return nil, fmt.Errorf("cannot create Projection: %w", err) } @@ -52,7 +52,7 @@ func (p *Projection) Register(ctx context.Context, deviceID string) (created boo }, func() interface{} { return kitSync.NewRefCounter(&deviceProjection{ deviceID: deviceID, - }, func(ctx context.Context, data interface{}) error { + }, func(_ context.Context, data interface{}) error { d := data.(*deviceProjection) d.released = true return nil @@ -75,7 +75,7 @@ func (p *Projection) Register(ctx context.Context, deviceID string) (created boo return errors.ErrorOrNil() } if updateSubscriber { - err := p.cqrsProjection.SubscribeTo(topics) + err = p.cqrsProjection.SubscribeTo(topics) if err != nil { return false, releaseAndReturnError(deviceID, err) } @@ -151,7 +151,7 @@ func (p *Projection) ForceUpdate(ctx context.Context, resourceID *commands.Resou func (p *Projection) release(v *kitSync.RefCounter) error { data := v.Data().(*deviceProjection) deviceID := data.deviceID - p.refCountMap.ReplaceWithFunc(deviceID, func(oldValue interface{}, oldLoaded bool) (newValue interface{}, doDelete bool) { + p.refCountMap.ReplaceWithFunc(deviceID, func(oldValue interface{}, _ bool) (newValue interface{}, doDelete bool) { o := oldValue.(*kitSync.RefCounter) d := o.Data().(*deviceProjection) if err := o.Release(context.Background()); err != nil { diff --git a/resource-aggregate/cqrs/projection/projectionInternal.go b/resource-aggregate/cqrs/projection/projectionInternal.go index f6b928521..3e981af6e 100644 --- a/resource-aggregate/cqrs/projection/projectionInternal.go +++ b/resource-aggregate/cqrs/projection/projectionInternal.go @@ -69,7 +69,7 @@ func (p *projection) SubscribeTo(topics []string) error { } if p.observer == nil { if p.subscriber == nil { - return fmt.Errorf("projection doesn't support subscribe to topics") + return errors.New("projection doesn't support subscribe to topics") } observer, err := p.subscriber.Subscribe(p.ctx, p.subscriptionID, topics, p) if err != nil { diff --git a/resource-aggregate/cqrs/projection/projectionInternal_test.go b/resource-aggregate/cqrs/projection/projectionInternal_test.go index cc0350bcc..301ede29c 100644 --- a/resource-aggregate/cqrs/projection/projectionInternal_test.go +++ b/resource-aggregate/cqrs/projection/projectionInternal_test.go @@ -21,7 +21,6 @@ import ( "github.com/plgd-dev/hub/v2/resource-aggregate/events" "github.com/plgd-dev/hub/v2/test" "github.com/plgd-dev/hub/v2/test/config" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace/noop" ) @@ -59,7 +58,7 @@ func TestProjection(t *testing.T) { naPubClient, publisher, err := natsTest.NewClientAndPublisher(config.MakePublisherConfig(), fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) - assert.NotNil(t, publisher) + require.NotNil(t, publisher) defer func() { publisher.Close() naPubClient.Close() @@ -74,8 +73,8 @@ func TestProjection(t *testing.T) { subscriber.WithGoPool(pool.Submit), subscriber.WithUnmarshaler(utils.Unmarshal), ) - assert.NoError(t, err) - assert.NotNil(t, subscriber) + require.NoError(t, err) + require.NotNil(t, subscriber) defer func() { subscriber.Close() naSubClient.Close() @@ -133,8 +132,8 @@ func TestProjection(t *testing.T) { CommandMetadata: &commands.CommandMetadata{}, } - a1, err := aggregate.NewAggregate(res1.DeviceId, res1.ToUUID().String(), aggregate.NewDefaultRetryFunc(1), store, func(context.Context) (aggregate.AggregateModel, error) { - s := events.NewResourceStateSnapshotTakenForCommand("test", "test", "hubID") + a1, err := aggregate.NewAggregate(res1.GetDeviceId(), res1.ToUUID().String(), aggregate.NewDefaultRetryFunc(1), store, func(context.Context, string, string) (aggregate.AggregateModel, error) { + s := events.NewResourceStateSnapshotTakenForCommand("test", "test", "hubID", nil) s.ResourceId = &res1 return s, nil }, nil) @@ -144,8 +143,8 @@ func TestProjection(t *testing.T) { require.NoError(t, err) require.NotNil(t, evs) - a2, err := aggregate.NewAggregate(res2.DeviceId, res2.ToUUID().String(), aggregate.NewDefaultRetryFunc(1), store, func(context.Context) (aggregate.AggregateModel, error) { - s := events.NewResourceStateSnapshotTakenForCommand("test", "test", "hubID") + a2, err := aggregate.NewAggregate(res2.GetDeviceId(), res2.ToUUID().String(), aggregate.NewDefaultRetryFunc(1), store, func(context.Context, string, string) (aggregate.AggregateModel, error) { + s := events.NewResourceStateSnapshotTakenForCommand("test", "test", "hubID", nil) s.ResourceId = &res2 return s, nil }, nil) @@ -159,7 +158,7 @@ func TestProjection(t *testing.T) { require.NoError(t, err) err = projection.Project(ctx, []eventstore.SnapshotQuery{{ - GroupID: res1.DeviceId, + GroupID: res1.GetDeviceId(), AggregateID: res1.ToUUID().String(), }}) require.NoError(t, err) @@ -168,10 +167,10 @@ func TestProjection(t *testing.T) { models = append(models, m) return true }) - require.Equal(t, 1, len(models)) + require.Len(t, models, 1) err = projection.Project(ctx, []eventstore.SnapshotQuery{{ - GroupID: res2.DeviceId, + GroupID: res2.GetDeviceId(), AggregateID: res2.ToUUID().String(), }}) require.NoError(t, err) @@ -180,15 +179,15 @@ func TestProjection(t *testing.T) { models = append(models, m) return true }) - require.Equal(t, 2, len(models)) + require.Len(t, models, 2) err = projection.SubscribeTo(topics) require.NoError(t, err) time.Sleep(waitForSubscription) - a3, err := aggregate.NewAggregate(res3.DeviceId, res3.ToUUID().String(), aggregate.NewDefaultRetryFunc(1), store, func(context.Context) (aggregate.AggregateModel, error) { - s := events.NewResourceStateSnapshotTakenForCommand("test", "test", "hubID") + a3, err := aggregate.NewAggregate(res3.GetDeviceId(), res3.ToUUID().String(), aggregate.NewDefaultRetryFunc(1), store, func(context.Context, string, string) (aggregate.AggregateModel, error) { + s := events.NewResourceStateSnapshotTakenForCommand("test", "test", "hubID", nil) s.ResourceId = &res3 return s, nil }, nil) @@ -198,7 +197,7 @@ func TestProjection(t *testing.T) { require.NoError(t, err) require.NotNil(t, evs) for _, e := range evs { - err = publisher.Publish(ctx, topics, res3.DeviceId, res3.ToUUID().String(), e) + err = publisher.Publish(ctx, topics, res3.GetDeviceId(), res3.ToUUID().String(), e) require.NoError(t, err) } time.Sleep(time.Second) @@ -208,7 +207,7 @@ func TestProjection(t *testing.T) { models = append(models, m) return true }) - require.Equal(t, 3, len(models)) + require.Len(t, models, 3) err = projection.SubscribeTo(topics[0:1]) require.NoError(t, err) @@ -216,7 +215,7 @@ func TestProjection(t *testing.T) { time.Sleep(waitForSubscription) err = projection.Forget([]eventstore.SnapshotQuery{{ - GroupID: res3.DeviceId, + GroupID: res3.GetDeviceId(), AggregateID: res3.ToUUID().String(), }}) require.NoError(t, err) @@ -229,7 +228,7 @@ func TestProjection(t *testing.T) { models = append(models, m) return true }) - require.Equal(t, 2, len(models)) + require.Len(t, models, 2) projection.lock.Unlock() err = projection.SubscribeTo(nil) @@ -243,7 +242,7 @@ func TestProjection(t *testing.T) { require.NoError(t, err) require.NotNil(t, evs) for _, e := range evs { - err = publisher.Publish(ctx, topics, res1.DeviceId, res1.ToUUID().String(), e) + err = publisher.Publish(ctx, topics, res1.GetDeviceId(), res1.ToUUID().String(), e) require.NoError(t, err) } @@ -253,6 +252,6 @@ func TestProjection(t *testing.T) { models = append(models, m) return true }) - require.Equal(t, 2, len(models)) + require.Len(t, models, 2) projection.lock.Unlock() } diff --git a/resource-aggregate/cqrs/projection/projection_test.go b/resource-aggregate/cqrs/projection/projection_test.go index 97ec0ffab..089b16191 100644 --- a/resource-aggregate/cqrs/projection/projection_test.go +++ b/resource-aggregate/cqrs/projection/projection_test.go @@ -22,68 +22,81 @@ var ( ) var d1res1 = commands.Resource{ - DeviceId: dev1, - Href: "/res1", + DeviceId: dev1, + Href: "/res1", + ResourceTypes: []string{"typeDev1Res"}, } var d1res2 = commands.Resource{ - DeviceId: dev1, - Href: "/res2", + DeviceId: dev1, + Href: "/res2", + ResourceTypes: []string{"typeDev1Res2"}, } var d1res3 = commands.Resource{ - DeviceId: dev1, - Href: "/res3", + DeviceId: dev1, + Href: "/res3", + ResourceTypes: []string{"typeDev1Res3"}, } var d1res4 = commands.Resource{ - DeviceId: dev1, - Href: "/res4", + DeviceId: dev1, + Href: "/res4", + ResourceTypes: []string{"typeDev1Res4"}, } var d1res5 = commands.Resource{ - DeviceId: dev1, - Href: "/res5", + DeviceId: dev1, + Href: "/res5", + ResourceTypes: []string{"typeDev1Res5"}, } var d2res1 = commands.Resource{ - DeviceId: dev2, - Href: "/res1", + DeviceId: dev2, + Href: "/res1", + ResourceTypes: []string{"typeDev2Res1"}, } var d2res2 = commands.Resource{ - DeviceId: dev2, - Href: "/res2", + DeviceId: dev2, + Href: "/res2", + ResourceTypes: []string{"typeDev2Res2"}, } var d3res1 = commands.Resource{ - DeviceId: "dev3", - Href: "/res1", + DeviceId: "dev3", + Href: "/res1", + ResourceTypes: []string{"typeDev3Res1"}, } var d3res2 = commands.Resource{ - DeviceId: "dev3", - Href: "/res2", + DeviceId: "dev3", + Href: "/res2", + ResourceTypes: []string{"typeDev3Res2"}, } var d4res1 = commands.Resource{ - DeviceId: "dev4", - Href: "/res1", + DeviceId: "dev4", + Href: "/res1", + ResourceTypes: []string{"typeDev4Res1"}, } var d4res2 = commands.Resource{ - DeviceId: "dev4", - Href: "/res2", + DeviceId: "dev4", + Href: "/res2", + ResourceTypes: []string{"typeDev4Res2"}, } var d5res1 = commands.Resource{ - DeviceId: "dev5", - Href: "/res1", + DeviceId: "dev5", + Href: "/res1", + ResourceTypes: []string{"typeDev5Res1"}, } var d5res2 = commands.Resource{ - DeviceId: "dev5", - Href: "/res2", + DeviceId: "dev5", + Href: "/res2", + ResourceTypes: []string{"typeDev5Res2"}, } func makeEventMeta(connectionID string, version uint64) *events.EventMetadata { @@ -95,32 +108,32 @@ func makeEventMeta(connectionID string, version uint64) *events.EventMetadata { func prepareResourceLinksEventstore() *mockEvents.MockEventStore { eventstore := mockEvents.NewMockEventStore() - d1resID := commands.MakeLinksResourceUUID(d1res1.DeviceId) - eventstore.Append(d1res1.DeviceId, d1resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d1res1}, d1res1.DeviceId, makeEventMeta("a", 0))) - eventstore.Append(d1res2.DeviceId, d1resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d1res2, &d1res3}, d1res2.DeviceId, makeEventMeta("a", 1))) - eventstore.Append(d1res2.DeviceId, d1resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d1res2.Href}, d1res2.DeviceId, makeEventMeta("a", 2))) - eventstore.Append(d1res4.DeviceId, d1resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d1res4, &d1res5}, d1res4.DeviceId, makeEventMeta("a", 3))) - - d2resID := commands.MakeLinksResourceUUID(d2res1.DeviceId) - eventstore.Append(d2res1.DeviceId, d2resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d2res1, &d2res2}, d2res1.DeviceId, makeEventMeta("a", 0))) - eventstore.Append(d2res1.DeviceId, d2resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d2res1.Href}, d2res1.DeviceId, makeEventMeta("a", 1))) - eventstore.Append(d2res2.DeviceId, d2resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d2res2.Href}, d2res2.DeviceId, makeEventMeta("a", 2))) - eventstore.Append(d2res2.DeviceId, d2resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d2res2.Href}, d2res2.DeviceId, makeEventMeta("a", 3))) - eventstore.Append(d2res1.DeviceId, d2resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d2res1, &d2res1}, d2res1.DeviceId, makeEventMeta("a", 4))) - eventstore.Append(d2res2.DeviceId, d2resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d2res2.Href, d2res2.Href}, d2res2.DeviceId, makeEventMeta("a", 5))) - eventstore.Append(d2res1.DeviceId, d2resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d2res1}, d2res1.DeviceId, makeEventMeta("a", 6))) - - d3resID := commands.MakeLinksResourceUUID(d3res1.DeviceId) - eventstore.Append(d3res1.DeviceId, d3resID.String(), mockEvents.MakeResourceLinksSnapshotTaken(map[string]*commands.Resource{d3res1.Href: &d3res1, d3res2.Href: &d3res2}, d3res1.DeviceId, makeEventMeta("a", 0))) - eventstore.Append(d3res1.DeviceId, d3resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d3res1.Href}, d3res1.DeviceId, makeEventMeta("a", 1))) - - d4resID := commands.MakeLinksResourceUUID(d4res1.DeviceId) - eventstore.Append(d4res1.DeviceId, d4resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d4res1, &d4res2}, d4res1.DeviceId, makeEventMeta("a", 0))) - eventstore.Append(d4res1.DeviceId, d4resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{}, d4res1.DeviceId, makeEventMeta("a", 1))) - - d5resID := commands.MakeLinksResourceUUID(d5res1.DeviceId) - eventstore.Append(d5res1.DeviceId, d5resID.String(), mockEvents.MakeResourceLinksSnapshotTaken(map[string]*commands.Resource{d5res1.Href: &d5res1, d5res2.Href: &d5res2}, d5res1.DeviceId, makeEventMeta("a", 0))) - eventstore.Append(d5res1.DeviceId, d5resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{}, d5res1.DeviceId, makeEventMeta("a", 1))) + d1resID := commands.MakeLinksResourceUUID(d1res1.GetDeviceId()) + eventstore.Append(d1res1.GetDeviceId(), d1resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d1res1}, d1res1.GetDeviceId(), makeEventMeta("a", 0))) + eventstore.Append(d1res2.GetDeviceId(), d1resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d1res2, &d1res3}, d1res2.GetDeviceId(), makeEventMeta("a", 1))) + eventstore.Append(d1res2.GetDeviceId(), d1resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d1res2.GetHref()}, d1res2.GetDeviceId(), makeEventMeta("a", 2))) + eventstore.Append(d1res4.GetDeviceId(), d1resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d1res4, &d1res5}, d1res4.GetDeviceId(), makeEventMeta("a", 3))) + + d2resID := commands.MakeLinksResourceUUID(d2res1.GetDeviceId()) + eventstore.Append(d2res1.GetDeviceId(), d2resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d2res1, &d2res2}, d2res1.GetDeviceId(), makeEventMeta("a", 0))) + eventstore.Append(d2res1.GetDeviceId(), d2resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d2res1.GetHref()}, d2res1.GetDeviceId(), makeEventMeta("a", 1))) + eventstore.Append(d2res2.GetDeviceId(), d2resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d2res2.GetHref()}, d2res2.GetDeviceId(), makeEventMeta("a", 2))) + eventstore.Append(d2res2.GetDeviceId(), d2resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d2res2.GetHref()}, d2res2.GetDeviceId(), makeEventMeta("a", 3))) + eventstore.Append(d2res1.GetDeviceId(), d2resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d2res1, &d2res1}, d2res1.GetDeviceId(), makeEventMeta("a", 4))) + eventstore.Append(d2res2.GetDeviceId(), d2resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d2res2.GetHref(), d2res2.GetHref()}, d2res2.GetDeviceId(), makeEventMeta("a", 5))) + eventstore.Append(d2res1.GetDeviceId(), d2resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d2res1}, d2res1.GetDeviceId(), makeEventMeta("a", 6))) + + d3resID := commands.MakeLinksResourceUUID(d3res1.GetDeviceId()) + eventstore.Append(d3res1.GetDeviceId(), d3resID.String(), mockEvents.MakeResourceLinksSnapshotTaken(map[string]*commands.Resource{d3res1.GetHref(): &d3res1, d3res2.GetHref(): &d3res2}, d3res1.GetDeviceId(), makeEventMeta("a", 0))) + eventstore.Append(d3res1.GetDeviceId(), d3resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{d3res1.GetHref()}, d3res1.GetDeviceId(), makeEventMeta("a", 1))) + + d4resID := commands.MakeLinksResourceUUID(d4res1.GetDeviceId()) + eventstore.Append(d4res1.GetDeviceId(), d4resID.String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{&d4res1, &d4res2}, d4res1.GetDeviceId(), makeEventMeta("a", 0))) + eventstore.Append(d4res1.GetDeviceId(), d4resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{}, d4res1.GetDeviceId(), makeEventMeta("a", 1))) + + d5resID := commands.MakeLinksResourceUUID(d5res1.GetDeviceId()) + eventstore.Append(d5res1.GetDeviceId(), d5resID.String(), mockEvents.MakeResourceLinksSnapshotTaken(map[string]*commands.Resource{d5res1.GetHref(): &d5res1, d5res2.GetHref(): &d5res2}, d5res1.GetDeviceId(), makeEventMeta("a", 0))) + eventstore.Append(d5res1.GetDeviceId(), d5resID.String(), mockEvents.MakeResourceLinksUnpublishedEvent([]string{}, d5res1.GetDeviceId(), makeEventMeta("a", 1))) return eventstore } @@ -129,38 +142,38 @@ func prepareResourceStateEventstore() *mockEvents.MockEventStore { eventstore := mockEvents.NewMockEventStore() resourceChangedEventMetadata := makeEventMeta("", 0) - d1r1 := commands.NewResourceID(d1res1.DeviceId, d1res1.Href) - eventstore.Append(d1res1.DeviceId, d1r1.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d1r1, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "0"))) - eventstore.Append(d1res1.DeviceId, d1r1.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r1, &commands.Content{}, makeEventMeta("a", 1), mockEvents.MakeAuditContext("userId", "1"), time.Time{})) - eventstore.Append(d1res1.DeviceId, d1r1.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r1, &commands.Content{}, makeEventMeta("a", 2), mockEvents.MakeAuditContext("userId", "2"), time.Time{})) - eventstore.Append(d1res1.DeviceId, d1r1.ToUUID().String(), mockEvents.MakeResourceUpdated(d1r1, commands.Status_OK, &commands.Content{}, makeEventMeta("a", 3), mockEvents.MakeAuditContext("userId", "1"))) - eventstore.Append(d1res1.DeviceId, d1r1.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r1, &commands.Content{}, makeEventMeta("a", 4), mockEvents.MakeAuditContext("userId", "3"), time.Time{})) - - d1r2 := commands.NewResourceID(d1res2.DeviceId, d1res2.Href) - eventstore.Append(d1res2.DeviceId, d1r2.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d1r2, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "2"))) - - d1r3 := commands.NewResourceID(d1res3.DeviceId, d1res3.Href) - eventstore.Append(d1res3.DeviceId, d1r3.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d1r3, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "2"))) - eventstore.Append(d1res3.DeviceId, d1r3.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r3, &commands.Content{}, makeEventMeta("a", 1), mockEvents.MakeAuditContext("userId", "3"), time.Time{})) - - d1r4 := commands.NewResourceID(d1res4.DeviceId, d1res4.Href) - eventstore.Append(d1res4.DeviceId, d1r4.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d1r4, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "0"))) - eventstore.Append(d1res4.DeviceId, d1r4.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r4, &commands.Content{}, makeEventMeta("a", 1), mockEvents.MakeAuditContext("userId", "1"), time.Time{})) - eventstore.Append(d1res4.DeviceId, d1r4.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r4, &commands.Content{}, makeEventMeta("a", 2), mockEvents.MakeAuditContext("userId", "2"), time.Time{})) - eventstore.Append(d1res4.DeviceId, d1r4.ToUUID().String(), mockEvents.MakeResourceUpdated(d1r4, commands.Status_OK, &commands.Content{}, makeEventMeta("a", 3), mockEvents.MakeAuditContext("userId", "1"))) - eventstore.Append(d1res4.DeviceId, d1r4.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d1r4, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata}, makeEventMeta("a", 4), mockEvents.MakeAuditContext("userId", "3"))) - eventstore.Append(d1res4.DeviceId, d1r4.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r4, &commands.Content{}, makeEventMeta("a", 5), mockEvents.MakeAuditContext("userId", "4"), time.Time{})) - - d2r1 := commands.NewResourceID(d2res1.DeviceId, d2res1.Href) - eventstore.Append(d2res1.DeviceId, d2r1.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d2r1, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "0"))) - eventstore.Append(d2res1.DeviceId, d2r1.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d2r1, &commands.Content{}, makeEventMeta("a", 1), mockEvents.MakeAuditContext("userId", "1"), time.Time{})) - eventstore.Append(d2res1.DeviceId, d2r1.ToUUID().String(), mockEvents.MakeResourceUpdated(d2r1, commands.Status_OK, &commands.Content{}, makeEventMeta("a", 2), mockEvents.MakeAuditContext("userId", "1"))) - - d2r2 := commands.NewResourceID(d2res2.DeviceId, d2res2.Href) - eventstore.Append(d2res2.DeviceId, d2r2.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d2r2, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "0"))) - eventstore.Append(d2res2.DeviceId, d2r2.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d2r2, &commands.Content{}, makeEventMeta("a", 1), mockEvents.MakeAuditContext("userId", "1"), time.Time{})) - eventstore.Append(d2res2.DeviceId, d2r2.ToUUID().String(), mockEvents.MakeResourceUpdated(d2r2, commands.Status_OK, &commands.Content{}, makeEventMeta("a", 2), mockEvents.MakeAuditContext("userId", "1"))) - eventstore.Append(d2res2.DeviceId, d2r2.ToUUID().String(), mockEvents.MakeResourceChangedEvent(d2r2, &commands.Content{}, makeEventMeta("a", 3), mockEvents.MakeAuditContext("userId", "2"))) + d1r1 := commands.NewResourceID(d1res1.GetDeviceId(), d1res1.GetHref()) + eventstore.Append(d1res1.GetDeviceId(), d1r1.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d1r1, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata, ResourceTypes: d1res1.GetResourceTypes()}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "0"), d1res1.GetResourceTypes())) + eventstore.Append(d1res1.GetDeviceId(), d1r1.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r1, &commands.Content{}, makeEventMeta("a", 1), mockEvents.MakeAuditContext("userId", "1"), time.Time{}, d1res1.GetResourceTypes())) + eventstore.Append(d1res1.GetDeviceId(), d1r1.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r1, &commands.Content{}, makeEventMeta("a", 2), mockEvents.MakeAuditContext("userId", "2"), time.Time{}, d1res1.GetResourceTypes())) + eventstore.Append(d1res1.GetDeviceId(), d1r1.ToUUID().String(), mockEvents.MakeResourceUpdated(d1r1, commands.Status_OK, &commands.Content{}, makeEventMeta("a", 3), mockEvents.MakeAuditContext("userId", "1"), d1res1.GetResourceTypes())) + eventstore.Append(d1res1.GetDeviceId(), d1r1.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r1, &commands.Content{}, makeEventMeta("a", 4), mockEvents.MakeAuditContext("userId", "3"), time.Time{}, d1res1.GetResourceTypes())) + + d1r2 := commands.NewResourceID(d1res2.GetDeviceId(), d1res2.GetHref()) + eventstore.Append(d1res2.GetDeviceId(), d1r2.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d1r2, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata, ResourceTypes: d1res2.GetResourceTypes()}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "2"), d1res2.GetResourceTypes())) + + d1r3 := commands.NewResourceID(d1res3.GetDeviceId(), d1res3.GetHref()) + eventstore.Append(d1res3.GetDeviceId(), d1r3.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d1r3, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata, ResourceTypes: d1res3.GetResourceTypes()}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "2"), d1res3.GetResourceTypes())) + eventstore.Append(d1res3.GetDeviceId(), d1r3.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r3, &commands.Content{}, makeEventMeta("a", 1), mockEvents.MakeAuditContext("userId", "3"), time.Time{}, d1res3.GetResourceTypes())) + + d1r4 := commands.NewResourceID(d1res4.GetDeviceId(), d1res4.GetHref()) + eventstore.Append(d1res4.GetDeviceId(), d1r4.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d1r4, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata, ResourceTypes: d1res4.GetResourceTypes()}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "0"), d1res4.GetResourceTypes())) + eventstore.Append(d1res4.GetDeviceId(), d1r4.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r4, &commands.Content{}, makeEventMeta("a", 1), mockEvents.MakeAuditContext("userId", "1"), time.Time{}, d1res4.GetResourceTypes())) + eventstore.Append(d1res4.GetDeviceId(), d1r4.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r4, &commands.Content{}, makeEventMeta("a", 2), mockEvents.MakeAuditContext("userId", "2"), time.Time{}, d1res4.GetResourceTypes())) + eventstore.Append(d1res4.GetDeviceId(), d1r4.ToUUID().String(), mockEvents.MakeResourceUpdated(d1r4, commands.Status_OK, &commands.Content{}, makeEventMeta("a", 3), mockEvents.MakeAuditContext("userId", "1"), d1res4.GetResourceTypes())) + eventstore.Append(d1res4.GetDeviceId(), d1r4.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d1r4, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata}, makeEventMeta("a", 4), mockEvents.MakeAuditContext("userId", "3"), d1res4.GetResourceTypes())) + eventstore.Append(d1res4.GetDeviceId(), d1r4.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d1r4, &commands.Content{}, makeEventMeta("a", 5), mockEvents.MakeAuditContext("userId", "4"), time.Time{}, d1res4.GetResourceTypes())) + + d2r1 := commands.NewResourceID(d2res1.GetDeviceId(), d2res1.GetHref()) + eventstore.Append(d2res1.GetDeviceId(), d2r1.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d2r1, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata, ResourceTypes: d2res1.GetResourceTypes()}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "0"), d2res1.GetResourceTypes())) + eventstore.Append(d2res1.GetDeviceId(), d2r1.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d2r1, &commands.Content{}, makeEventMeta("a", 1), mockEvents.MakeAuditContext("userId", "1"), time.Time{}, d2res1.GetResourceTypes())) + eventstore.Append(d2res1.GetDeviceId(), d2r1.ToUUID().String(), mockEvents.MakeResourceUpdated(d2r1, commands.Status_OK, &commands.Content{}, makeEventMeta("a", 2), mockEvents.MakeAuditContext("userId", "1"), d2res1.GetResourceTypes())) + + d2r2 := commands.NewResourceID(d2res2.GetDeviceId(), d2res2.GetHref()) + eventstore.Append(d2res2.GetDeviceId(), d2r2.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(d2r2, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata, ResourceTypes: d2res2.GetResourceTypes()}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "0"), d2res2.GetResourceTypes())) + eventstore.Append(d2res2.GetDeviceId(), d2r2.ToUUID().String(), mockEvents.MakeResourceUpdatePending(d2r2, &commands.Content{}, makeEventMeta("a", 1), mockEvents.MakeAuditContext("userId", "1"), time.Time{}, d2res2.GetResourceTypes())) + eventstore.Append(d2res2.GetDeviceId(), d2r2.ToUUID().String(), mockEvents.MakeResourceUpdated(d2r2, commands.Status_OK, &commands.Content{}, makeEventMeta("a", 2), mockEvents.MakeAuditContext("userId", "1"), d2res2.GetResourceTypes())) + eventstore.Append(d2res2.GetDeviceId(), d2r2.ToUUID().String(), mockEvents.MakeResourceChangedEvent(d2r2, &commands.Content{}, makeEventMeta("a", 3), mockEvents.MakeAuditContext("userId", "2"), d2res2.GetResourceTypes())) return eventstore } @@ -175,7 +188,7 @@ func TestResourceProjectionTestLoadParallelModels(t *testing.T) { for i := 0; i < numDevices; i++ { for j := 0; j < numResources; j++ { resourceID := commands.NewResourceID(fmt.Sprintf("dev-%v", i), fmt.Sprintf("res-%v", j)) - eventstore.Append(resourceID.GetDeviceId(), resourceID.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(resourceID, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "2"))) + eventstore.Append(resourceID.GetDeviceId(), resourceID.ToUUID().String(), mockEvents.MakeResourceStateSnapshotTaken(resourceID, &events.ResourceChanged{Content: &commands.Content{}, EventMetadata: resourceChangedEventMetadata}, makeEventMeta("a", 0), mockEvents.MakeAuditContext("userId", "2"), []string{"type1", "type2"})) } } @@ -185,7 +198,7 @@ func TestResourceProjectionTestLoadParallelModels(t *testing.T) { "test", eventstore, nil, - func(ctx context.Context, groupID, aggregateID string) (cqrsEventStore.Model, error) { + func(_ context.Context, _, _ string) (cqrsEventStore.Model, error) { return events.NewResourceLinksSnapshotTaken(), nil }, ) @@ -201,7 +214,7 @@ func TestResourceProjectionTestLoadParallelModels(t *testing.T) { go func(v int) { defer wg.Done() n := time.Now() - p.cqrsProjection.Models(nil, func(m cqrsEventStore.Model) (wantNext bool) { return true }) + p.cqrsProjection.Models(nil, func(cqrsEventStore.Model) (wantNext bool) { return true }) diff := -1 * time.Until(n) t.Logf("%v models time %v\n", v, diff) }(i) @@ -222,14 +235,14 @@ func TestResourceProjection_Register(t *testing.T) { { name: "first valid", args: args{ - deviceID: d1res1.DeviceId, + deviceID: d1res1.GetDeviceId(), }, wantLoaded: true, }, { name: "second valid", args: args{ - deviceID: d1res1.DeviceId, + deviceID: d1res1.GetDeviceId(), }, }, { @@ -248,11 +261,11 @@ func TestResourceProjection_Register(t *testing.T) { "test", eventstore, nil, - func(ctx context.Context, groupID, aggregateID string) (cqrsEventStore.Model, error) { + func(_ context.Context, _, _ string) (cqrsEventStore.Model, error) { return events.NewResourceLinksSnapshotTaken(), nil }, ) - assert.NoError(t, err) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -263,9 +276,9 @@ func TestResourceProjection_Register(t *testing.T) { assert.False(t, gotLoaded) } if tt.wantErr { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) + require.NoError(t, err) } }) } @@ -283,26 +296,26 @@ func TestResourceProjection_Unregister(t *testing.T) { { name: "first time", args: args{ - deviceID: d1res1.DeviceId, + deviceID: d1res1.GetDeviceId(), }, }, { - name: "second second", + name: "second time", args: args{ - deviceID: d1res1.DeviceId, + deviceID: d1res1.GetDeviceId(), }, }, { name: "third error", args: args{ - deviceID: d1res1.DeviceId, + deviceID: d1res1.GetDeviceId(), }, wantErr: true, }, { name: "not registered", args: args{ - deviceID: d2res1.DeviceId, + deviceID: d2res1.GetDeviceId(), }, wantErr: true, }, @@ -315,23 +328,23 @@ func TestResourceProjection_Unregister(t *testing.T) { "test", eventstore, nil, - func(ctx context.Context, groupID, aggregateID string) (cqrsEventStore.Model, error) { + func(_ context.Context, _, _ string) (cqrsEventStore.Model, error) { return events.NewResourceLinksSnapshotTaken(), nil }, ) - assert.NoError(t, err) - _, err = p.Register(ctx, d1res1.DeviceId) - assert.NoError(t, err) - _, err = p.Register(ctx, d1res1.DeviceId) - assert.NoError(t, err) + require.NoError(t, err) + _, err = p.Register(ctx, d1res1.GetDeviceId()) + require.NoError(t, err) + _, err = p.Register(ctx, d1res1.GetDeviceId()) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := p.Unregister(tt.args.deviceID) if tt.wantErr { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) + require.NoError(t, err) } }) } @@ -349,17 +362,17 @@ func TestResourceLinksProjection_Models(t *testing.T) { { name: "valid dev1", args: args{ - deviceID: d1res1.DeviceId, + deviceID: d1res1.GetDeviceId(), }, want: []cqrsEventStore.Model{ &events.ResourceLinksSnapshotTaken{ Resources: map[string]*commands.Resource{ - d1res1.Href: &d1res1, - d1res3.Href: &d1res3, - d1res4.Href: &d1res4, - d1res5.Href: &d1res5, + d1res1.GetHref(): &d1res1, + d1res3.GetHref(): &d1res3, + d1res4.GetHref(): &d1res4, + d1res5.GetHref(): &d1res5, }, - DeviceId: d1res1.DeviceId, + DeviceId: d1res1.GetDeviceId(), EventMetadata: &events.EventMetadata{ Version: 3, Timestamp: 12345, @@ -372,14 +385,14 @@ func TestResourceLinksProjection_Models(t *testing.T) { { name: "valid dev2", args: args{ - deviceID: d2res1.DeviceId, + deviceID: d2res1.GetDeviceId(), }, want: []cqrsEventStore.Model{ &events.ResourceLinksSnapshotTaken{ Resources: map[string]*commands.Resource{ - d2res1.Href: &d2res1, + d2res1.GetHref(): &d2res1, }, - DeviceId: d2res1.DeviceId, + DeviceId: d2res1.GetDeviceId(), EventMetadata: &events.EventMetadata{ Version: 6, Timestamp: 12345, @@ -392,14 +405,14 @@ func TestResourceLinksProjection_Models(t *testing.T) { { name: "valid dev3", args: args{ - deviceID: d3res2.DeviceId, + deviceID: d3res2.GetDeviceId(), }, want: []cqrsEventStore.Model{ &events.ResourceLinksSnapshotTaken{ Resources: map[string]*commands.Resource{ - d3res2.Href: &d3res2, + d3res2.GetHref(): &d3res2, }, - DeviceId: d3res2.DeviceId, + DeviceId: d3res2.GetDeviceId(), EventMetadata: &events.EventMetadata{ Version: 1, Timestamp: 12345, @@ -412,12 +425,12 @@ func TestResourceLinksProjection_Models(t *testing.T) { { name: "valid dev4", args: args{ - deviceID: d4res1.DeviceId, + deviceID: d4res1.GetDeviceId(), }, want: []cqrsEventStore.Model{ &events.ResourceLinksSnapshotTaken{ Resources: map[string]*commands.Resource{}, - DeviceId: d4res1.DeviceId, + DeviceId: d4res1.GetDeviceId(), EventMetadata: &events.EventMetadata{ Version: 1, Timestamp: 12345, @@ -430,12 +443,12 @@ func TestResourceLinksProjection_Models(t *testing.T) { { name: "valid dev5", args: args{ - deviceID: d5res1.DeviceId, + deviceID: d5res1.GetDeviceId(), }, want: []cqrsEventStore.Model{ &events.ResourceLinksSnapshotTaken{ Resources: map[string]*commands.Resource{}, - DeviceId: d5res1.DeviceId, + DeviceId: d5res1.GetDeviceId(), EventMetadata: &events.EventMetadata{ Version: 1, Timestamp: 12345, @@ -454,16 +467,16 @@ func TestResourceLinksProjection_Models(t *testing.T) { "test", eventstore, nil, - func(ctx context.Context, groupID, aggregateID string) (cqrsEventStore.Model, error) { + func(_ context.Context, _, _ string) (cqrsEventStore.Model, error) { return events.NewResourceLinksSnapshotTaken(), nil }, ) - assert.NoError(t, err) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err = p.Register(ctx, tt.args.deviceID) - assert.NoError(t, err) + require.NoError(t, err) got := []cqrsEventStore.Model{} p.Models(func(m cqrsEventStore.Model) (wantNext bool) { got = append(got, m) @@ -486,7 +499,7 @@ func TestResourceLinksProjection_Models(t *testing.T) { } } -func TestResourceStateProjection_Models(t *testing.T) { +func TestResourceStateProjectionModels(t *testing.T) { type args struct { resourceID *commands.ResourceId } @@ -498,16 +511,17 @@ func TestResourceStateProjection_Models(t *testing.T) { { name: "valid dev1r1", args: args{ - resourceID: commands.NewResourceID(d1res1.DeviceId, d1res1.Href), + resourceID: commands.NewResourceID(d1res1.GetDeviceId(), d1res1.GetHref()), }, want: []cqrsEventStore.Model{ &events.ResourceStateSnapshotTaken{ - ResourceId: commands.NewResourceID(d1res1.DeviceId, d1res1.Href), + ResourceId: commands.NewResourceID(d1res1.GetDeviceId(), d1res1.GetHref()), LatestResourceChange: &events.ResourceChanged{ Content: &commands.Content{}, EventMetadata: &events.EventMetadata{ Timestamp: 12345, }, + ResourceTypes: d1res1.GetResourceTypes(), }, EventMetadata: &events.EventMetadata{ Version: 4, @@ -520,7 +534,7 @@ func TestResourceStateProjection_Models(t *testing.T) { }, ResourceUpdatePendings: []*events.ResourceUpdatePending{ { - ResourceId: commands.NewResourceID(d1res1.DeviceId, d1res1.Href), + ResourceId: commands.NewResourceID(d1res1.GetDeviceId(), d1res1.GetHref()), Content: &commands.Content{}, AuditContext: &commands.AuditContext{ UserId: "userId", @@ -531,9 +545,10 @@ func TestResourceStateProjection_Models(t *testing.T) { Timestamp: 12345, ConnectionId: "a", }, + ResourceTypes: d1res1.GetResourceTypes(), }, { - ResourceId: commands.NewResourceID(d1res1.DeviceId, d1res1.Href), + ResourceId: commands.NewResourceID(d1res1.GetDeviceId(), d1res1.GetHref()), Content: &commands.Content{}, AuditContext: &commands.AuditContext{ UserId: "userId", @@ -544,47 +559,52 @@ func TestResourceStateProjection_Models(t *testing.T) { Timestamp: 12345, ConnectionId: "a", }, + ResourceTypes: d1res1.GetResourceTypes(), }, }, + ResourceTypes: d1res1.GetResourceTypes(), }, }, }, { name: "valid dev1r2", args: args{ - resourceID: commands.NewResourceID(d1res2.DeviceId, d1res2.Href), + resourceID: commands.NewResourceID(d1res2.GetDeviceId(), d1res2.GetHref()), }, want: []cqrsEventStore.Model{ &events.ResourceStateSnapshotTaken{ - ResourceId: commands.NewResourceID(d1res2.DeviceId, d1res2.Href), + ResourceId: commands.NewResourceID(d1res2.GetDeviceId(), d1res2.GetHref()), LatestResourceChange: &events.ResourceChanged{ Content: &commands.Content{}, EventMetadata: &events.EventMetadata{ Timestamp: 12345, }, + ResourceTypes: d1res2.GetResourceTypes(), }, EventMetadata: &events.EventMetadata{ Version: 0, Timestamp: 12345, ConnectionId: "a", }, - AuditContext: commands.NewAuditContext("userId", "2", ""), + AuditContext: commands.NewAuditContext("userId", "2", ""), + ResourceTypes: d1res2.GetResourceTypes(), }, }, }, { name: "valid dev1r3", args: args{ - resourceID: commands.NewResourceID(d1res3.DeviceId, d1res3.Href), + resourceID: commands.NewResourceID(d1res3.GetDeviceId(), d1res3.GetHref()), }, want: []cqrsEventStore.Model{ &events.ResourceStateSnapshotTaken{ - ResourceId: commands.NewResourceID(d1res3.DeviceId, d1res3.Href), + ResourceId: commands.NewResourceID(d1res3.GetDeviceId(), d1res3.GetHref()), LatestResourceChange: &events.ResourceChanged{ Content: &commands.Content{}, EventMetadata: &events.EventMetadata{ Timestamp: 12345, }, + ResourceTypes: d1res3.GetResourceTypes(), }, EventMetadata: &events.EventMetadata{ Version: 1, @@ -597,7 +617,7 @@ func TestResourceStateProjection_Models(t *testing.T) { }, ResourceUpdatePendings: []*events.ResourceUpdatePending{ { - ResourceId: commands.NewResourceID(d1res3.DeviceId, d1res3.Href), + ResourceId: commands.NewResourceID(d1res3.GetDeviceId(), d1res3.GetHref()), Content: &commands.Content{}, AuditContext: &commands.AuditContext{ UserId: "userId", @@ -608,8 +628,10 @@ func TestResourceStateProjection_Models(t *testing.T) { Timestamp: 12345, ConnectionId: "a", }, + ResourceTypes: d1res3.GetResourceTypes(), }, }, + ResourceTypes: d1res3.GetResourceTypes(), }, }, }, @@ -617,11 +639,11 @@ func TestResourceStateProjection_Models(t *testing.T) { { name: "valid dev1r4", args: args{ - resourceID: commands.NewResourceID(d1res4.DeviceId, d1res4.Href), + resourceID: commands.NewResourceID(d1res4.GetDeviceId(), d1res4.GetHref()), }, want: []cqrsEventStore.Model{ &events.ResourceStateSnapshotTaken{ - ResourceId: commands.NewResourceID(d1res4.DeviceId, d1res4.Href), + ResourceId: commands.NewResourceID(d1res4.GetDeviceId(), d1res4.GetHref()), LatestResourceChange: &events.ResourceChanged{ Content: &commands.Content{}, EventMetadata: &events.EventMetadata{ @@ -639,7 +661,7 @@ func TestResourceStateProjection_Models(t *testing.T) { }, ResourceUpdatePendings: []*events.ResourceUpdatePending{ { - ResourceId: commands.NewResourceID(d1res4.DeviceId, d1res4.Href), + ResourceId: commands.NewResourceID(d1res4.GetDeviceId(), d1res4.GetHref()), Content: &commands.Content{}, AuditContext: &commands.AuditContext{ UserId: "userId", @@ -650,24 +672,27 @@ func TestResourceStateProjection_Models(t *testing.T) { Timestamp: 12345, ConnectionId: "a", }, + ResourceTypes: d1res4.GetResourceTypes(), }, }, + ResourceTypes: d1res4.GetResourceTypes(), }, }, }, { name: "valid dev2r1", args: args{ - resourceID: commands.NewResourceID(d2res1.DeviceId, d2res1.Href), + resourceID: commands.NewResourceID(d2res1.GetDeviceId(), d2res1.GetHref()), }, want: []cqrsEventStore.Model{ &events.ResourceStateSnapshotTaken{ - ResourceId: commands.NewResourceID(d2res1.DeviceId, d2res1.Href), + ResourceId: commands.NewResourceID(d2res1.GetDeviceId(), d2res1.GetHref()), LatestResourceChange: &events.ResourceChanged{ Content: &commands.Content{}, EventMetadata: &events.EventMetadata{ Timestamp: 12345, }, + ResourceTypes: d2res1.GetResourceTypes(), }, EventMetadata: &events.EventMetadata{ Version: 2, @@ -679,19 +704,20 @@ func TestResourceStateProjection_Models(t *testing.T) { CorrelationId: "1", }, ResourceUpdatePendings: []*events.ResourceUpdatePending{}, + ResourceTypes: d2res1.GetResourceTypes(), }, }, }, { name: "valid dev2r2", args: args{ - resourceID: commands.NewResourceID(d2res2.DeviceId, d2res2.Href), + resourceID: commands.NewResourceID(d2res2.GetDeviceId(), d2res2.GetHref()), }, want: []cqrsEventStore.Model{ &events.ResourceStateSnapshotTaken{ - ResourceId: commands.NewResourceID(d2res2.DeviceId, d2res2.Href), + ResourceId: commands.NewResourceID(d2res2.GetDeviceId(), d2res2.GetHref()), LatestResourceChange: &events.ResourceChanged{ - ResourceId: commands.NewResourceID(d2res2.DeviceId, d2res2.Href), + ResourceId: commands.NewResourceID(d2res2.GetDeviceId(), d2res2.GetHref()), Content: &commands.Content{}, AuditContext: &commands.AuditContext{UserId: "userId", CorrelationId: "2"}, EventMetadata: &events.EventMetadata{ @@ -699,6 +725,7 @@ func TestResourceStateProjection_Models(t *testing.T) { Timestamp: 12345, ConnectionId: "a", }, + ResourceTypes: d2res2.GetResourceTypes(), }, EventMetadata: &events.EventMetadata{ Version: 3, @@ -710,6 +737,7 @@ func TestResourceStateProjection_Models(t *testing.T) { CorrelationId: "2", }, ResourceUpdatePendings: []*events.ResourceUpdatePending{}, + ResourceTypes: d2res2.GetResourceTypes(), }, }, }, @@ -722,16 +750,16 @@ func TestResourceStateProjection_Models(t *testing.T) { "test", eventstore, nil, - func(ctx context.Context, groupID, aggregateID string) (cqrsEventStore.Model, error) { + func(_ context.Context, _, _ string) (cqrsEventStore.Model, error) { return events.NewResourceStateSnapshotTaken(), nil }, ) - assert.NoError(t, err) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err = p.Register(ctx, tt.args.resourceID.GetDeviceId()) - assert.NoError(t, err) + require.NoError(t, err) got := []cqrsEventStore.Model{} p.Models(func(m cqrsEventStore.Model) (wantNext bool) { got = append(got, m) @@ -766,7 +794,7 @@ func TestResourceProjection_ForceUpdate(t *testing.T) { { name: "valid", args: args{ - resourceID: commands.NewResourceID(d1res1.DeviceId, d1res1.Href), + resourceID: commands.NewResourceID(d1res1.GetDeviceId(), d1res1.GetHref()), }, }, { @@ -785,20 +813,20 @@ func TestResourceProjection_ForceUpdate(t *testing.T) { "test", eventstore, nil, - func(ctx context.Context, groupID, aggregateID string) (cqrsEventStore.Model, error) { + func(_ context.Context, _, _ string) (cqrsEventStore.Model, error) { return events.NewResourceStateSnapshotTaken(), nil }, ) - assert.NoError(t, err) - _, err = p.Register(ctx, d1res1.DeviceId) - assert.NoError(t, err) + require.NoError(t, err) + _, err = p.Register(ctx, d1res1.GetDeviceId()) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := p.ForceUpdate(ctx, tt.args.resourceID) if tt.wantErr { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) + require.NoError(t, err) } }) } diff --git a/resource-aggregate/cqrs/utils/utils_test.go b/resource-aggregate/cqrs/utils/utils_test.go index 2c91ac99b..75d294e57 100644 --- a/resource-aggregate/cqrs/utils/utils_test.go +++ b/resource-aggregate/cqrs/utils/utils_test.go @@ -7,6 +7,7 @@ import ( "github.com/plgd-dev/hub/v2/resource-aggregate/cqrs/utils" "github.com/plgd-dev/hub/v2/resource-aggregate/events" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestDummyForCoverage(t *testing.T) { @@ -21,30 +22,30 @@ func TestDummyForCoverage(t *testing.T) { hubID := "h" em := events.MakeEventMeta(connID, sequence, version, hubID) - assert.Equal(t, connID, em.ConnectionId) - assert.Equal(t, sequence, em.Sequence) - assert.Equal(t, version, em.Version) - assert.Equal(t, hubID, em.HubId) + assert.Equal(t, connID, em.GetConnectionId()) + assert.Equal(t, sequence, em.GetSequence()) + assert.Equal(t, version, em.GetVersion()) + assert.Equal(t, hubID, em.GetHubId()) ac := commands.NewAuditContext(userID, corID, userID) - assert.Equal(t, corID, ac.CorrelationId) - assert.Equal(t, userID, ac.UserId) + assert.Equal(t, corID, ac.GetCorrelationId()) + assert.Equal(t, userID, ac.GetUserId()) } func TestProtobufMarshaler(t *testing.T) { req := events.ResourceChanged{} out, err := utils.Marshal(&req) - assert.NoError(t, err) + require.NoError(t, err) assert.NotEmpty(t, out) a := struct{}{} _, err = utils.Marshal(a) - assert.Error(t, err) + require.Error(t, err) resp := events.ResourceChanged{} err = utils.Unmarshal(out, &resp) - assert.NoError(t, err) + require.NoError(t, err) err = utils.Unmarshal(out, a) - assert.Error(t, err) + require.Error(t, err) } diff --git a/resource-aggregate/events/deviceMetadataSnapshotTaken.go b/resource-aggregate/events/deviceMetadataSnapshotTaken.go index e213803da..2e896fe01 100644 --- a/resource-aggregate/events/deviceMetadataSnapshotTaken.go +++ b/resource-aggregate/events/deviceMetadataSnapshotTaken.go @@ -58,6 +58,10 @@ func (d *DeviceMetadataSnapshotTaken) ServiceID() (string, bool) { return d.GetDeviceMetadataUpdated().GetConnection().GetServiceId(), true } +func (d *DeviceMetadataSnapshotTaken) Types() []string { + return nil +} + func (d *DeviceMetadataSnapshotTaken) CopyData(event *DeviceMetadataSnapshotTaken) { d.DeviceId = event.GetDeviceId() d.DeviceMetadataUpdated = event.GetDeviceMetadataUpdated() @@ -74,7 +78,8 @@ func (d *DeviceMetadataSnapshotTaken) CheckInitialized() bool { func (d *DeviceMetadataSnapshotTaken) HandleDeviceMetadataUpdated(_ context.Context, upd *DeviceMetadataUpdated, confirm bool) (bool, error) { index := -1 - for i, event := range d.GetUpdatePendings() { + updatePendings := d.GetUpdatePendings() + for i, event := range updatePendings { if event.GetAuditContext().GetCorrelationId() == upd.GetAuditContext().GetCorrelationId() { index = i break @@ -84,9 +89,10 @@ func (d *DeviceMetadataSnapshotTaken) HandleDeviceMetadataUpdated(_ context.Cont return false, status.Errorf(codes.InvalidArgument, "cannot find twin synchronization update pending event with correlationId('%v')", upd.GetAuditContext().GetCorrelationId()) } if index >= 0 { - d.UpdatePendings = append(d.UpdatePendings[:index], d.UpdatePendings[index+1:]...) + updatePendings = append(updatePendings[:index], updatePendings[index+1:]...) + d.UpdatePendings = updatePendings } - if d.DeviceMetadataUpdated.Equal(upd) { + if d.GetDeviceMetadataUpdated().Equal(upd) { return false, nil } @@ -321,9 +327,9 @@ func (d *DeviceMetadataSnapshotTaken) getTwinSynchronizationForConnectedDevice(r func (d *DeviceMetadataSnapshotTaken) getTwinSynchronizationForDisconnectedDevice(req *commands.UpdateDeviceMetadataRequest) (*commands.TwinSynchronization, error) { twinSynchronization := d.prepareTwinSynchronization() - if d.DeviceMetadataUpdated.GetConnection().IsOnline() && !req.GetConnection().IsOnline() && d.DeviceMetadataUpdated.GetConnection().GetId() != req.GetConnection().GetId() { + if d.GetDeviceMetadataUpdated().GetConnection().IsOnline() && !req.GetConnection().IsOnline() && d.GetDeviceMetadataUpdated().GetConnection().GetId() != req.GetConnection().GetId() { // if previous status was online and new status is offline, the connectionId must be the same - return nil, status.Errorf(codes.InvalidArgument, "cannot update connection status online(id='%v') to offline(id='%v'): connectionId mismatch", d.DeviceMetadataUpdated.GetConnection().GetId(), req.GetConnection().GetId()) + return nil, status.Errorf(codes.InvalidArgument, "cannot update connection status online(id='%v') to offline(id='%v'): connectionId mismatch", d.GetDeviceMetadataUpdated().GetConnection().GetId(), req.GetConnection().GetId()) } if d.GetDeviceMetadataUpdated().GetTwinEnabled() { twinSynchronization.State = commands.TwinSynchronization_OUT_OF_SYNC @@ -356,6 +362,11 @@ func (d *DeviceMetadataSnapshotTaken) updateDeviceConnection(ctx context.Context req.GetConnection().ConnectedAt = lastConnectedAt } + // keep local endpoints from the previous event + if len(req.GetConnection().GetLocalEndpoints()) == 0 { + req.GetConnection().LocalEndpoints = d.GetDeviceMetadataUpdated().GetConnection().GetLocalEndpoints() + } + getTwinSynchronization := d.getTwinSynchronizationForDisconnectedDevice if req.GetConnection().IsOnline() { getTwinSynchronization = d.getTwinSynchronizationForConnectedDevice diff --git a/resource-aggregate/events/deviceMetadataSnapshotTaken_test.go b/resource-aggregate/events/deviceMetadataSnapshotTaken_test.go index 444e765fe..eb7189ce4 100644 --- a/resource-aggregate/events/deviceMetadataSnapshotTaken_test.go +++ b/resource-aggregate/events/deviceMetadataSnapshotTaken_test.go @@ -16,13 +16,16 @@ import ( "google.golang.org/protobuf/proto" ) +var localEndpoints = []string{"coap://localhost:5683"} + var testEventDeviceMetadataSnapshotTaken events.DeviceMetadataSnapshotTaken = events.DeviceMetadataSnapshotTaken{ DeviceId: dev1, DeviceMetadataUpdated: &events.DeviceMetadataUpdated{ DeviceId: dev1, Connection: &commands.Connection{ - Status: commands.Connection_ONLINE, - Id: "con1", + Status: commands.Connection_ONLINE, + Id: "con1", + LocalEndpoints: localEndpoints, }, TwinEnabled: true, AuditContext: &commands.AuditContext{ @@ -170,9 +173,10 @@ func TestDeviceMetadataSnapshotTakenHandleCommand(t *testing.T) { CorrelationId: correlationID, Update: &commands.UpdateDeviceMetadataRequest_Connection{ Connection: &commands.Connection{ - Status: commands.Connection_ONLINE, - ConnectedAt: connectedAt, - Protocol: commands.Connection_COAPS, + Status: commands.Connection_ONLINE, + ConnectedAt: connectedAt, + Protocol: commands.Connection_COAPS, + LocalEndpoints: localEndpoints, }, }, }, @@ -181,9 +185,10 @@ func TestDeviceMetadataSnapshotTakenHandleCommand(t *testing.T) { pb.ToEvent(&events.DeviceMetadataUpdated{ DeviceId: deviceID, Connection: &commands.Connection{ - Status: commands.Connection_ONLINE, - ConnectedAt: connectedAt, - Protocol: commands.Connection_COAPS, + Status: commands.Connection_ONLINE, + ConnectedAt: connectedAt, + Protocol: commands.Connection_COAPS, + LocalEndpoints: localEndpoints, }, TwinEnabled: true, TwinSynchronization: &commands.TwinSynchronization{}, @@ -230,9 +235,10 @@ func TestDeviceMetadataSnapshotTakenHandleCommand(t *testing.T) { pb.ToEvent(&events.DeviceMetadataUpdated{ DeviceId: deviceID, Connection: &commands.Connection{ - Status: commands.Connection_OFFLINE, - ConnectedAt: connectedAt, - Protocol: commands.Connection_COAPS, + Status: commands.Connection_OFFLINE, + ConnectedAt: connectedAt, + Protocol: commands.Connection_COAPS, + LocalEndpoints: localEndpoints, }, TwinEnabled: true, TwinSynchronization: &commands.TwinSynchronization{}, diff --git a/resource-aggregate/events/deviceMetadataUpdatePending.go b/resource-aggregate/events/deviceMetadataUpdatePending.go index 2506b5d59..6d86da1c3 100644 --- a/resource-aggregate/events/deviceMetadataUpdatePending.go +++ b/resource-aggregate/events/deviceMetadataUpdatePending.go @@ -47,6 +47,10 @@ func (d *DeviceMetadataUpdatePending) ETag() *eventstore.ETagData { return nil } +func (d *DeviceMetadataUpdatePending) Types() []string { + return nil +} + func (d *DeviceMetadataUpdatePending) CopyData(event *DeviceMetadataUpdatePending) { d.DeviceId = event.GetDeviceId() d.UpdatePending = event.GetUpdatePending() diff --git a/resource-aggregate/events/deviceMetadataUpdated.go b/resource-aggregate/events/deviceMetadataUpdated.go index 86c56fd19..e446f3660 100644 --- a/resource-aggregate/events/deviceMetadataUpdated.go +++ b/resource-aggregate/events/deviceMetadataUpdated.go @@ -6,6 +6,7 @@ import ( pkgTime "github.com/plgd-dev/hub/v2/pkg/time" commands "github.com/plgd-dev/hub/v2/resource-aggregate/commands" "github.com/plgd-dev/hub/v2/resource-aggregate/cqrs/eventstore" + "golang.org/x/exp/slices" "google.golang.org/protobuf/proto" ) @@ -51,6 +52,10 @@ func (d *DeviceMetadataUpdated) ServiceID() (string, bool) { return d.GetConnection().GetServiceId(), true } +func (d *DeviceMetadataUpdated) Types() []string { + return nil +} + func (d *DeviceMetadataUpdated) CopyData(event *DeviceMetadataUpdated) { d.DeviceId = event.GetDeviceId() d.Connection = event.GetConnection() @@ -74,6 +79,7 @@ func (d *DeviceMetadataUpdated) Equal(upd *DeviceMetadataUpdated) bool { return d.GetConnection().GetStatus() == upd.GetConnection().GetStatus() && d.GetConnection().GetId() == upd.GetConnection().GetId() && d.GetConnection().GetProtocol() == upd.GetConnection().GetProtocol() && + slices.Equal(d.GetConnection().GetLocalEndpoints(), upd.GetConnection().GetLocalEndpoints()) && d.GetCanceled() == upd.GetCanceled() && d.GetTwinEnabled() == upd.GetTwinEnabled() && d.GetAuditContext().GetUserId() == upd.GetAuditContext().GetUserId() && diff --git a/resource-aggregate/events/deviceMetadataUpdated_test.go b/resource-aggregate/events/deviceMetadataUpdated_test.go index c5af85f82..c5f0a394c 100644 --- a/resource-aggregate/events/deviceMetadataUpdated_test.go +++ b/resource-aggregate/events/deviceMetadataUpdated_test.go @@ -48,9 +48,9 @@ func TestDeviceMetadataUpdated_Equal(t *testing.T) { { name: "Identity", fields: fields{ - Connection: upd.Connection, - TwinEnabled: upd.TwinEnabled, - AuditContext: upd.AuditContext, + Connection: upd.GetConnection(), + TwinEnabled: upd.GetTwinEnabled(), + AuditContext: upd.GetAuditContext(), }, args: args{upd}, want: true, @@ -61,8 +61,8 @@ func TestDeviceMetadataUpdated_Equal(t *testing.T) { Connection: &commands.Connection{ Status: commands.Connection_OFFLINE, }, - TwinEnabled: upd.TwinEnabled, - AuditContext: upd.AuditContext, + TwinEnabled: upd.GetTwinEnabled(), + AuditContext: upd.GetAuditContext(), }, args: args{upd}, want: false, @@ -70,9 +70,9 @@ func TestDeviceMetadataUpdated_Equal(t *testing.T) { { name: "Changed TwinSynchronization", fields: fields{ - Connection: upd.Connection, + Connection: upd.GetConnection(), TwinEnabled: false, - AuditContext: upd.AuditContext, + AuditContext: upd.GetAuditContext(), }, args: args{upd}, want: false, @@ -80,11 +80,11 @@ func TestDeviceMetadataUpdated_Equal(t *testing.T) { { name: "Changed AuditContext.UserId", fields: fields{ - Connection: upd.Connection, - TwinEnabled: upd.TwinEnabled, + Connection: upd.GetConnection(), + TwinEnabled: upd.GetTwinEnabled(), AuditContext: &commands.AuditContext{ - UserId: upd.AuditContext.UserId + "0", - CorrelationId: upd.AuditContext.CorrelationId, + UserId: upd.GetAuditContext().GetUserId() + "0", + CorrelationId: upd.GetAuditContext().GetCorrelationId(), }, }, args: args{upd}, @@ -93,11 +93,11 @@ func TestDeviceMetadataUpdated_Equal(t *testing.T) { { name: "Changed AuditContext.CorrelationId", fields: fields{ - Connection: upd.Connection, - TwinEnabled: upd.TwinEnabled, + Connection: upd.GetConnection(), + TwinEnabled: upd.GetTwinEnabled(), AuditContext: &commands.AuditContext{ - UserId: upd.AuditContext.UserId, - CorrelationId: upd.AuditContext.CorrelationId + "0", + UserId: upd.GetAuditContext().GetUserId(), + CorrelationId: upd.GetAuditContext().GetCorrelationId() + "0", }, }, args: args{upd}, diff --git a/resource-aggregate/events/events.pb.go b/resource-aggregate/events/events.pb.go index c5c2d3ac4..4ffd3be2d 100644 --- a/resource-aggregate/events/events.pb.go +++ b/resource-aggregate/events/events.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: resource-aggregate/pb/events.proto package events @@ -344,6 +344,7 @@ type ResourceChanged struct { AuditContext *commands.AuditContext `protobuf:"bytes,4,opt,name=audit_context,json=auditContext,proto3" json:"audit_context,omitempty"` EventMetadata *EventMetadata `protobuf:"bytes,5,opt,name=event_metadata,json=eventMetadata,proto3" json:"event_metadata,omitempty"` Etag []byte `protobuf:"bytes,6,opt,name=etag,proto3" json:"etag,omitempty"` // etag of the resource used by twin synchronization + ResourceTypes []string `protobuf:"bytes,7,rep,name=resource_types,json=resourceTypes,proto3" json:"resource_types,omitempty"` // Open telemetry data propagated to asynchronous events OpenTelemetryCarrier map[string]string `protobuf:"bytes,100,rep,name=open_telemetry_carrier,json=openTelemetryCarrier,proto3" json:"open_telemetry_carrier,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -422,6 +423,13 @@ func (x *ResourceChanged) GetEtag() []byte { return nil } +func (x *ResourceChanged) GetResourceTypes() []string { + if x != nil { + return x.ResourceTypes + } + return nil +} + func (x *ResourceChanged) GetOpenTelemetryCarrier() map[string]string { if x != nil { return x.OpenTelemetryCarrier @@ -440,6 +448,7 @@ type ResourceUpdatePending struct { AuditContext *commands.AuditContext `protobuf:"bytes,4,opt,name=audit_context,json=auditContext,proto3" json:"audit_context,omitempty"` EventMetadata *EventMetadata `protobuf:"bytes,5,opt,name=event_metadata,json=eventMetadata,proto3" json:"event_metadata,omitempty"` ValidUntil int64 `protobuf:"varint,6,opt,name=valid_until,json=validUntil,proto3" json:"valid_until,omitempty"` // unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. + ResourceTypes []string `protobuf:"bytes,7,rep,name=resource_types,json=resourceTypes,proto3" json:"resource_types,omitempty"` // Open telemetry data propagated to asynchronous events OpenTelemetryCarrier map[string]string `protobuf:"bytes,100,rep,name=open_telemetry_carrier,json=openTelemetryCarrier,proto3" json:"open_telemetry_carrier,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -518,6 +527,13 @@ func (x *ResourceUpdatePending) GetValidUntil() int64 { return 0 } +func (x *ResourceUpdatePending) GetResourceTypes() []string { + if x != nil { + return x.ResourceTypes + } + return nil +} + func (x *ResourceUpdatePending) GetOpenTelemetryCarrier() map[string]string { if x != nil { return x.OpenTelemetryCarrier @@ -535,6 +551,7 @@ type ResourceUpdated struct { Content *commands.Content `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` AuditContext *commands.AuditContext `protobuf:"bytes,4,opt,name=audit_context,json=auditContext,proto3" json:"audit_context,omitempty"` EventMetadata *EventMetadata `protobuf:"bytes,5,opt,name=event_metadata,json=eventMetadata,proto3" json:"event_metadata,omitempty"` + ResourceTypes []string `protobuf:"bytes,6,rep,name=resource_types,json=resourceTypes,proto3" json:"resource_types,omitempty"` // Open telemetry data propagated to asynchronous events OpenTelemetryCarrier map[string]string `protobuf:"bytes,100,rep,name=open_telemetry_carrier,json=openTelemetryCarrier,proto3" json:"open_telemetry_carrier,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -606,6 +623,13 @@ func (x *ResourceUpdated) GetEventMetadata() *EventMetadata { return nil } +func (x *ResourceUpdated) GetResourceTypes() []string { + if x != nil { + return x.ResourceTypes + } + return nil +} + func (x *ResourceUpdated) GetOpenTelemetryCarrier() map[string]string { if x != nil { return x.OpenTelemetryCarrier @@ -624,6 +648,7 @@ type ResourceRetrievePending struct { EventMetadata *EventMetadata `protobuf:"bytes,4,opt,name=event_metadata,json=eventMetadata,proto3" json:"event_metadata,omitempty"` ValidUntil int64 `protobuf:"varint,5,opt,name=valid_until,json=validUntil,proto3" json:"valid_until,omitempty"` // unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. Etag [][]byte `protobuf:"bytes,6,rep,name=etag,proto3" json:"etag,omitempty"` + ResourceTypes []string `protobuf:"bytes,7,rep,name=resource_types,json=resourceTypes,proto3" json:"resource_types,omitempty"` // Open telemetry data propagated to asynchronous events OpenTelemetryCarrier map[string]string `protobuf:"bytes,100,rep,name=open_telemetry_carrier,json=openTelemetryCarrier,proto3" json:"open_telemetry_carrier,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -702,6 +727,13 @@ func (x *ResourceRetrievePending) GetEtag() [][]byte { return nil } +func (x *ResourceRetrievePending) GetResourceTypes() []string { + if x != nil { + return x.ResourceTypes + } + return nil +} + func (x *ResourceRetrievePending) GetOpenTelemetryCarrier() map[string]string { if x != nil { return x.OpenTelemetryCarrier @@ -720,6 +752,7 @@ type ResourceRetrieved struct { AuditContext *commands.AuditContext `protobuf:"bytes,4,opt,name=audit_context,json=auditContext,proto3" json:"audit_context,omitempty"` EventMetadata *EventMetadata `protobuf:"bytes,5,opt,name=event_metadata,json=eventMetadata,proto3" json:"event_metadata,omitempty"` Etag []byte `protobuf:"bytes,6,opt,name=etag,proto3" json:"etag,omitempty"` + ResourceTypes []string `protobuf:"bytes,7,rep,name=resource_types,json=resourceTypes,proto3" json:"resource_types,omitempty"` // Open telemetry data propagated to asynchronous events OpenTelemetryCarrier map[string]string `protobuf:"bytes,100,rep,name=open_telemetry_carrier,json=openTelemetryCarrier,proto3" json:"open_telemetry_carrier,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -798,6 +831,13 @@ func (x *ResourceRetrieved) GetEtag() []byte { return nil } +func (x *ResourceRetrieved) GetResourceTypes() []string { + if x != nil { + return x.ResourceTypes + } + return nil +} + func (x *ResourceRetrieved) GetOpenTelemetryCarrier() map[string]string { if x != nil { return x.OpenTelemetryCarrier @@ -815,6 +855,7 @@ type ResourceDeletePending struct { EventMetadata *EventMetadata `protobuf:"bytes,3,opt,name=event_metadata,json=eventMetadata,proto3" json:"event_metadata,omitempty"` ValidUntil int64 `protobuf:"varint,4,opt,name=valid_until,json=validUntil,proto3" json:"valid_until,omitempty"` // unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. ResourceInterface string `protobuf:"bytes,5,opt,name=resource_interface,json=resourceInterface,proto3" json:"resource_interface,omitempty"` + ResourceTypes []string `protobuf:"bytes,6,rep,name=resource_types,json=resourceTypes,proto3" json:"resource_types,omitempty"` // Open telemetry data propagated to asynchronous events OpenTelemetryCarrier map[string]string `protobuf:"bytes,100,rep,name=open_telemetry_carrier,json=openTelemetryCarrier,proto3" json:"open_telemetry_carrier,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -886,6 +927,13 @@ func (x *ResourceDeletePending) GetResourceInterface() string { return "" } +func (x *ResourceDeletePending) GetResourceTypes() []string { + if x != nil { + return x.ResourceTypes + } + return nil +} + func (x *ResourceDeletePending) GetOpenTelemetryCarrier() map[string]string { if x != nil { return x.OpenTelemetryCarrier @@ -903,6 +951,7 @@ type ResourceDeleted struct { Content *commands.Content `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` AuditContext *commands.AuditContext `protobuf:"bytes,4,opt,name=audit_context,json=auditContext,proto3" json:"audit_context,omitempty"` EventMetadata *EventMetadata `protobuf:"bytes,5,opt,name=event_metadata,json=eventMetadata,proto3" json:"event_metadata,omitempty"` + ResourceTypes []string `protobuf:"bytes,6,rep,name=resource_types,json=resourceTypes,proto3" json:"resource_types,omitempty"` // Open telemetry data propagated to asynchronous events OpenTelemetryCarrier map[string]string `protobuf:"bytes,100,rep,name=open_telemetry_carrier,json=openTelemetryCarrier,proto3" json:"open_telemetry_carrier,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -974,6 +1023,13 @@ func (x *ResourceDeleted) GetEventMetadata() *EventMetadata { return nil } +func (x *ResourceDeleted) GetResourceTypes() []string { + if x != nil { + return x.ResourceTypes + } + return nil +} + func (x *ResourceDeleted) GetOpenTelemetryCarrier() map[string]string { if x != nil { return x.OpenTelemetryCarrier @@ -991,6 +1047,7 @@ type ResourceCreatePending struct { AuditContext *commands.AuditContext `protobuf:"bytes,3,opt,name=audit_context,json=auditContext,proto3" json:"audit_context,omitempty"` EventMetadata *EventMetadata `protobuf:"bytes,4,opt,name=event_metadata,json=eventMetadata,proto3" json:"event_metadata,omitempty"` ValidUntil int64 `protobuf:"varint,5,opt,name=valid_until,json=validUntil,proto3" json:"valid_until,omitempty"` // unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. + ResourceTypes []string `protobuf:"bytes,6,rep,name=resource_types,json=resourceTypes,proto3" json:"resource_types,omitempty"` // Open telemetry data propagated to asynchronous events OpenTelemetryCarrier map[string]string `protobuf:"bytes,100,rep,name=open_telemetry_carrier,json=openTelemetryCarrier,proto3" json:"open_telemetry_carrier,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -1062,6 +1119,13 @@ func (x *ResourceCreatePending) GetValidUntil() int64 { return 0 } +func (x *ResourceCreatePending) GetResourceTypes() []string { + if x != nil { + return x.ResourceTypes + } + return nil +} + func (x *ResourceCreatePending) GetOpenTelemetryCarrier() map[string]string { if x != nil { return x.OpenTelemetryCarrier @@ -1079,6 +1143,7 @@ type ResourceCreated struct { Content *commands.Content `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` AuditContext *commands.AuditContext `protobuf:"bytes,4,opt,name=audit_context,json=auditContext,proto3" json:"audit_context,omitempty"` EventMetadata *EventMetadata `protobuf:"bytes,5,opt,name=event_metadata,json=eventMetadata,proto3" json:"event_metadata,omitempty"` + ResourceTypes []string `protobuf:"bytes,6,rep,name=resource_types,json=resourceTypes,proto3" json:"resource_types,omitempty"` // Open telemetry data propagated to asynchronous events OpenTelemetryCarrier map[string]string `protobuf:"bytes,100,rep,name=open_telemetry_carrier,json=openTelemetryCarrier,proto3" json:"open_telemetry_carrier,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -1150,6 +1215,13 @@ func (x *ResourceCreated) GetEventMetadata() *EventMetadata { return nil } +func (x *ResourceCreated) GetResourceTypes() []string { + if x != nil { + return x.ResourceTypes + } + return nil +} + func (x *ResourceCreated) GetOpenTelemetryCarrier() map[string]string { if x != nil { return x.OpenTelemetryCarrier @@ -1170,6 +1242,7 @@ type ResourceStateSnapshotTaken struct { ResourceDeletePendings []*ResourceDeletePending `protobuf:"bytes,6,rep,name=resource_delete_pendings,json=resourceDeletePendings,proto3" json:"resource_delete_pendings,omitempty"` // expired events will be removed by creating a new snapshot. AuditContext *commands.AuditContext `protobuf:"bytes,7,opt,name=audit_context,json=auditContext,proto3" json:"audit_context,omitempty"` EventMetadata *EventMetadata `protobuf:"bytes,8,opt,name=event_metadata,json=eventMetadata,proto3" json:"event_metadata,omitempty"` + ResourceTypes []string `protobuf:"bytes,9,rep,name=resource_types,json=resourceTypes,proto3" json:"resource_types,omitempty"` } func (x *ResourceStateSnapshotTaken) Reset() { @@ -1260,6 +1333,13 @@ func (x *ResourceStateSnapshotTaken) GetEventMetadata() *EventMetadata { return nil } +func (x *ResourceStateSnapshotTaken) GetResourceTypes() []string { + if x != nil { + return x.ResourceTypes + } + return nil +} + type DeviceMetadataUpdated struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1897,7 +1977,7 @@ var file_resource_aggregate_pb_events_proto_rawDesc = []byte{ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xac, 0x04, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd3, 0x04, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, @@ -1920,28 +2000,69 @@ var file_resource_aggregate_pb_events_proto_rawDesc = []byte{ 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x75, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, - 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x2e, 0x4f, 0x70, - 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, - 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, - 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, - 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, - 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xbe, 0x04, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, - 0x63, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, + 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x75, 0x0a, + 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, + 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, + 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, + 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, + 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, + 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xe5, 0x04, + 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, + 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, + 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, + 0x7b, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, + 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x45, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, + 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, + 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, + 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, + 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, + 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xbf, 0x04, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, + 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0d, 0x61, @@ -1954,13 +2075,122 @@ var file_resource_aggregate_pb_events_proto_rawDesc = []byte{ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, - 0x6c, 0x12, 0x7b, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, + 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x75, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, + 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, + 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, + 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, + 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, + 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, + 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc4, 0x04, 0x0a, 0x17, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, + 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x65, + 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, + 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x7d, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, + 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x47, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, + 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, + 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, + 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd7, + 0x04, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, + 0x65, 0x76, 0x65, 0x64, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, + 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, + 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x65, + 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, + 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x77, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, + 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, 0x2e, + 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, + 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, + 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, + 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xac, 0x04, 0x0a, 0x15, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, + 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x73, 0x12, 0x7b, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x4f, + 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, @@ -1968,8 +2198,8 @@ var file_resource_aggregate_pb_events_proto_rawDesc = []byte{ 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x98, 0x04, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x41, 0x0a, 0x0b, 0x72, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xbf, 0x04, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, @@ -1990,11 +2220,49 @@ var file_resource_aggregate_pb_events_proto_rawDesc = []byte{ 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x75, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, - 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, + 0x74, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x75, 0x0a, 0x16, 0x6f, 0x70, 0x65, + 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, + 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, + 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, + 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, + 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, + 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xb6, 0x04, 0x0a, 0x15, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, + 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, + 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, + 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, + 0x74, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x7b, 0x0a, 0x16, + 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, + 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, @@ -2002,33 +2270,124 @@ var file_resource_aggregate_pb_events_proto_rawDesc = []byte{ 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0x9d, 0x04, 0x0a, 0x17, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, - 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x41, - 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, - 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, - 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, - 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x75, - 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x7d, 0x0a, 0x16, 0x6f, 0x70, - 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, - 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x47, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, - 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, + 0x38, 0x01, 0x22, 0xbf, 0x04, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, + 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, + 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x25, 0x0a, + 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x73, 0x12, 0x75, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, + 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, + 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, + 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, + 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, + 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x9a, 0x06, 0x0a, 0x1a, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x54, 0x61, + 0x6b, 0x65, 0x6e, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x5b, 0x0a, 0x16, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, + 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x14, 0x6c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x12, 0x65, 0x0a, 0x18, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x52, 0x16, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x6b, 0x0a, 0x1a, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x5f, + 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, + 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x18, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, + 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x65, 0x0a, 0x18, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, + 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x16, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x65, + 0x0a, 0x18, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x16, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, + 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x73, 0x22, 0xf4, 0x04, 0x0a, 0x15, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x40, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5c, 0x0a, 0x14, 0x74, 0x77, + 0x69, 0x6e, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x54, 0x77, 0x69, 0x6e, 0x53, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x74, 0x77, 0x69, 0x6e, 0x53, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, + 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x77, 0x69, 0x6e, + 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, + 0x74, 0x77, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x47, 0x0a, 0x0d, 0x61, + 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x7b, 0x0a, 0x16, + 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, + 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, @@ -2036,66 +2395,33 @@ var file_resource_aggregate_pb_events_proto_rawDesc = []byte{ 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0xb0, 0x04, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, - 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, - 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, - 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x38, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0xba, 0x04, 0x0a, 0x1b, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0c, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0b, 0x74, + 0x77, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x3e, 0x0a, 0x1a, 0x74, 0x77, + 0x69, 0x6e, 0x5f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, + 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, + 0x52, 0x18, 0x74, 0x77, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x68, + 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, + 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, - 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x65, - 0x74, 0x61, 0x67, 0x12, 0x77, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, - 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, - 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, - 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, - 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, - 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, - 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x85, 0x04, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, - 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x49, 0x64, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, - 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, - 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, - 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, - 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, + 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, + 0x12, 0x81, 0x01, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, + 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x4b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, @@ -2103,221 +2429,66 @@ var file_resource_aggregate_pb_events_proto_rawDesc = []byte{ 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x98, 0x04, - 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x64, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, - 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, 0x0a, 0x0e, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x75, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, - 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, - 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x2e, - 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, - 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, - 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, - 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8f, 0x04, 0x0a, 0x15, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x47, - 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, - 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, - 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, - 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, - 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x7b, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, - 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, - 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, - 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, - 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, - 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x98, 0x04, 0x0a, 0x0f, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x41, - 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, - 0x64, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, - 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, - 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x75, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, - 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, - 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, - 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, - 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, - 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, - 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, - 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xf3, 0x05, 0x0a, 0x1a, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x54, - 0x61, 0x6b, 0x65, 0x6e, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x5b, 0x0a, 0x16, 0x6c, 0x61, 0x74, 0x65, 0x73, - 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x14, - 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x12, 0x65, 0x0a, 0x18, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x52, 0x16, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x6b, 0x0a, 0x1a, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, - 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, - 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, - 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x18, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, - 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x65, 0x0a, 0x18, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x16, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, - 0x65, 0x0a, 0x18, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x16, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, - 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf4, 0x04, 0x0a, 0x15, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x10, 0x0a, + 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4a, + 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0xc7, 0x02, 0x0a, 0x1b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x54, 0x61, 0x6b, 0x65, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x49, 0x64, 0x12, 0x40, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5c, 0x0a, 0x14, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x73, 0x79, 0x6e, - 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x77, 0x69, 0x6e, 0x53, 0x79, - 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x74, - 0x77, 0x69, 0x6e, 0x53, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x74, 0x77, 0x69, 0x6e, 0x45, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, - 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, - 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, - 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x7b, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, - 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, - 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, - 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, - 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, - 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, - 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x03, - 0x10, 0x04, 0x22, 0xba, 0x04, 0x0a, 0x1b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, - 0x23, 0x0a, 0x0c, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0b, 0x74, 0x77, 0x69, 0x6e, 0x45, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x12, 0x3e, 0x0a, 0x1a, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x66, 0x6f, 0x72, - 0x63, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x18, 0x74, 0x77, 0x69, 0x6e, - 0x46, 0x6f, 0x72, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, + 0x49, 0x64, 0x12, 0x63, 0x0a, 0x17, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x52, 0x15, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x5a, 0x0a, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x31, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x52, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x73, 0x12, 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, - 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x4a, 0x0a, - 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x81, 0x01, 0x0a, 0x16, 0x6f, - 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, - 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4b, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x4f, + 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, + 0xf6, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x48, 0x65, 0x61, 0x72, + 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x47, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x2e, 0x48, 0x65, + 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x4b, + 0x0a, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x31, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x48, + 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, + 0x61, 0x74, 0x52, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x1a, 0x4b, 0x0a, 0x09, 0x48, + 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x22, 0xcc, 0x03, 0x0a, 0x16, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x12, 0x56, 0x0a, 0x12, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x5f, + 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x48, + 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x11, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x12, 0x7c, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, + 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x46, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, @@ -2325,91 +2496,25 @@ var file_resource_aggregate_pb_events_proto_rawDesc = []byte{ 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x10, 0x0a, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, - 0xc7, 0x02, 0x0a, 0x1b, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x54, 0x61, 0x6b, 0x65, 0x6e, 0x12, - 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x63, 0x0a, 0x17, - 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x52, 0x15, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x64, 0x12, 0x5a, 0x0a, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x0e, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4a, 0x0a, - 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf6, 0x01, 0x0a, 0x11, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, - 0x47, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, - 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x48, 0x65, - 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, - 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x4b, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x69, - 0x72, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, - 0x61, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x07, 0x65, 0x78, - 0x70, 0x69, 0x72, 0x65, 0x64, 0x1a, 0x4b, 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, - 0x61, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, - 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, - 0x69, 0x6c, 0x22, 0xcc, 0x03, 0x0a, 0x16, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x56, 0x0a, - 0x12, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x5f, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, - 0x65, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, - 0x61, 0x74, 0x52, 0x11, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x48, 0x65, 0x61, 0x72, - 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0c, 0x61, 0x75, - 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x7c, 0x0a, 0x16, 0x6f, 0x70, - 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, - 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x72, 0x65, 0x73, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd2, 0x01, 0x0a, 0x1c, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x54, 0x61, 0x6b, 0x65, 0x6e, 0x12, 0x66, 0x0a, 0x18, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, - 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, - 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, - 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0xd2, 0x01, 0x0a, 0x1c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x54, 0x61, 0x6b, - 0x65, 0x6e, 0x12, 0x66, 0x0a, 0x18, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x64, 0x52, 0x16, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x4a, 0x0a, 0x0e, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, - 0x62, 0x2f, 0x76, 0x32, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2d, 0x61, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x52, 0x16, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x12, 0x4a, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x3d, 0x5a, 0x3b, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d, + 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x2f, 0x76, 0x32, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2d, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/resource-aggregate/events/resourceChanged.go b/resource-aggregate/events/resourceChanged.go index f4c694d12..91cb5d649 100644 --- a/resource-aggregate/events/resourceChanged.go +++ b/resource-aggregate/events/resourceChanged.go @@ -7,6 +7,7 @@ import ( pkgTime "github.com/plgd-dev/hub/v2/pkg/time" commands "github.com/plgd-dev/hub/v2/resource-aggregate/commands" "github.com/plgd-dev/hub/v2/resource-aggregate/cqrs/eventstore" + "golang.org/x/exp/slices" "google.golang.org/protobuf/proto" ) @@ -58,6 +59,10 @@ func (rc *ResourceChanged) ServiceID() (string, bool) { return "", false } +func (rc *ResourceChanged) Types() []string { + return rc.GetResourceTypes() +} + func (rc *ResourceChanged) CopyData(event *ResourceChanged) { rc.ResourceId = event.GetResourceId() rc.Content = event.GetContent() @@ -66,6 +71,7 @@ func (rc *ResourceChanged) CopyData(event *ResourceChanged) { rc.Status = event.GetStatus() rc.OpenTelemetryCarrier = event.GetOpenTelemetryCarrier() rc.Etag = event.GetEtag() + rc.ResourceTypes = event.GetResourceTypes() } func (rc *ResourceChanged) CheckInitialized() bool { @@ -90,6 +96,9 @@ func (rc *ResourceChanged) Equal(changed *ResourceChanged) bool { if rc.GetAuditContext().GetUserId() != changed.GetAuditContext().GetUserId() { return false } + if !slices.Equal(rc.GetResourceTypes(), changed.GetResourceTypes()) { + return false + } return true } diff --git a/resource-aggregate/events/resourceChanged_test.go b/resource-aggregate/events/resourceChanged_test.go index 500204d94..bda33bf20 100644 --- a/resource-aggregate/events/resourceChanged_test.go +++ b/resource-aggregate/events/resourceChanged_test.go @@ -30,10 +30,11 @@ var testEventResourceChanged events.ResourceChanged = events.ResourceChanged{ ConnectionId: "con1", Sequence: 1, }, - Status: commands.Status_ACCEPTED, + Status: commands.Status_ACCEPTED, + ResourceTypes: []string{"type1", "type2"}, } -func TestResourceChanged_CopyData(t *testing.T) { +func TestResourceChangedCopyData(t *testing.T) { type args struct { event *events.ResourceChanged } diff --git a/resource-aggregate/events/resourceCreatePending.go b/resource-aggregate/events/resourceCreatePending.go index 3934a7c01..87c7d43a4 100644 --- a/resource-aggregate/events/resourceCreatePending.go +++ b/resource-aggregate/events/resourceCreatePending.go @@ -50,6 +50,10 @@ func (e *ResourceCreatePending) ServiceID() (string, bool) { return "", false } +func (e *ResourceCreatePending) Types() []string { + return e.GetResourceTypes() +} + func (e *ResourceCreatePending) CopyData(event *ResourceCreatePending) { e.ResourceId = event.GetResourceId() e.Content = event.GetContent() @@ -57,6 +61,7 @@ func (e *ResourceCreatePending) CopyData(event *ResourceCreatePending) { e.EventMetadata = event.GetEventMetadata() e.ValidUntil = event.GetValidUntil() e.OpenTelemetryCarrier = event.GetOpenTelemetryCarrier() + e.ResourceTypes = event.GetResourceTypes() } func (e *ResourceCreatePending) CheckInitialized() bool { diff --git a/resource-aggregate/events/resourceCreatePending_test.go b/resource-aggregate/events/resourceCreatePending_test.go index a2a45790f..5858142d6 100644 --- a/resource-aggregate/events/resourceCreatePending_test.go +++ b/resource-aggregate/events/resourceCreatePending_test.go @@ -30,6 +30,7 @@ var testEventResourceCreatePending events.ResourceCreatePending = events.Resourc ConnectionId: "con1", Sequence: 1, }, + ResourceTypes: []string{"type1", "type2"}, } func TestResourceCreatePending_CopyData(t *testing.T) { diff --git a/resource-aggregate/events/resourceCreated.go b/resource-aggregate/events/resourceCreated.go index c826136ea..1bc4cb380 100644 --- a/resource-aggregate/events/resourceCreated.go +++ b/resource-aggregate/events/resourceCreated.go @@ -51,6 +51,10 @@ func (e *ResourceCreated) ServiceID() (string, bool) { return "", false } +func (e *ResourceCreated) Types() []string { + return e.GetResourceTypes() +} + func (e *ResourceCreated) CopyData(event *ResourceCreated) { e.ResourceId = event.GetResourceId() e.Status = event.GetStatus() @@ -58,6 +62,7 @@ func (e *ResourceCreated) CopyData(event *ResourceCreated) { e.AuditContext = event.GetAuditContext() e.EventMetadata = event.GetEventMetadata() e.OpenTelemetryCarrier = event.GetOpenTelemetryCarrier() + e.ResourceTypes = event.GetResourceTypes() } func (e *ResourceCreated) CheckInitialized() bool { diff --git a/resource-aggregate/events/resourceCreated_test.go b/resource-aggregate/events/resourceCreated_test.go index 93efddb2a..e2983d14d 100644 --- a/resource-aggregate/events/resourceCreated_test.go +++ b/resource-aggregate/events/resourceCreated_test.go @@ -31,9 +31,10 @@ var testEventResourceCreated events.ResourceCreated = events.ResourceCreated{ ConnectionId: "con1", Sequence: 1, }, + ResourceTypes: []string{"type1", "type2"}, } -func TestResourceCreated_CopyData(t *testing.T) { +func TestResourceCreatedCopyData(t *testing.T) { type args struct { event *events.ResourceCreated } diff --git a/resource-aggregate/events/resourceDeletePending.go b/resource-aggregate/events/resourceDeletePending.go index ef12ee02f..477fee130 100644 --- a/resource-aggregate/events/resourceDeletePending.go +++ b/resource-aggregate/events/resourceDeletePending.go @@ -50,6 +50,10 @@ func (e *ResourceDeletePending) ServiceID() (string, bool) { return "", false } +func (e *ResourceDeletePending) Types() []string { + return e.GetResourceTypes() +} + func (e *ResourceDeletePending) CopyData(event *ResourceDeletePending) { e.ResourceId = event.GetResourceId() e.AuditContext = event.GetAuditContext() @@ -57,6 +61,7 @@ func (e *ResourceDeletePending) CopyData(event *ResourceDeletePending) { e.ValidUntil = event.GetValidUntil() e.ResourceInterface = event.GetResourceInterface() e.OpenTelemetryCarrier = event.GetOpenTelemetryCarrier() + e.ResourceTypes = event.GetResourceTypes() } func (e *ResourceDeletePending) CheckInitialized() bool { diff --git a/resource-aggregate/events/resourceDeletePending_test.go b/resource-aggregate/events/resourceDeletePending_test.go index 1a629c707..a6964408b 100644 --- a/resource-aggregate/events/resourceDeletePending_test.go +++ b/resource-aggregate/events/resourceDeletePending_test.go @@ -26,9 +26,10 @@ var testEventResourceDeletePending events.ResourceDeletePending = events.Resourc Sequence: 1, }, ResourceInterface: interfaces.OC_IF_BASELINE, + ResourceTypes: []string{"type1", "type2"}, } -func TestResourceDeletePending_CopyData(t *testing.T) { +func TestResourceDeletePendingCopyData(t *testing.T) { type args struct { event *events.ResourceDeletePending } diff --git a/resource-aggregate/events/resourceDeleted.go b/resource-aggregate/events/resourceDeleted.go index feb9047e0..1f4ab2d3b 100644 --- a/resource-aggregate/events/resourceDeleted.go +++ b/resource-aggregate/events/resourceDeleted.go @@ -51,6 +51,10 @@ func (e *ResourceDeleted) ServiceID() (string, bool) { return "", false } +func (e *ResourceDeleted) Types() []string { + return e.GetResourceTypes() +} + func (e *ResourceDeleted) CopyData(event *ResourceDeleted) { e.ResourceId = event.GetResourceId() e.Status = event.GetStatus() @@ -58,6 +62,7 @@ func (e *ResourceDeleted) CopyData(event *ResourceDeleted) { e.AuditContext = event.GetAuditContext() e.EventMetadata = event.GetEventMetadata() e.OpenTelemetryCarrier = event.GetOpenTelemetryCarrier() + e.ResourceTypes = event.GetResourceTypes() } func (e *ResourceDeleted) CheckInitialized() bool { diff --git a/resource-aggregate/events/resourceDeleted_test.go b/resource-aggregate/events/resourceDeleted_test.go index 89fe66bb0..c34b44244 100644 --- a/resource-aggregate/events/resourceDeleted_test.go +++ b/resource-aggregate/events/resourceDeleted_test.go @@ -31,6 +31,7 @@ var testEventResourceDeleted events.ResourceDeleted = events.ResourceDeleted{ ConnectionId: "con1", Sequence: 1, }, + ResourceTypes: []string{"type1", "type2"}, } func TestResourceDeleted_CopyData(t *testing.T) { diff --git a/resource-aggregate/events/resourceLinksPublished.go b/resource-aggregate/events/resourceLinksPublished.go index 3c361dfc8..e3e32426e 100644 --- a/resource-aggregate/events/resourceLinksPublished.go +++ b/resource-aggregate/events/resourceLinksPublished.go @@ -51,6 +51,10 @@ func (e *ResourceLinksPublished) ServiceID() (string, bool) { return "", false } +func (e *ResourceLinksPublished) Types() []string { + return nil +} + func (e *ResourceLinksPublished) CopyData(event *ResourceLinksPublished) { e.Resources = event.GetResources() e.DeviceId = event.GetDeviceId() diff --git a/resource-aggregate/events/resourceLinksSnapshotTaken.go b/resource-aggregate/events/resourceLinksSnapshotTaken.go index a4a46c59b..654b1bdec 100644 --- a/resource-aggregate/events/resourceLinksSnapshotTaken.go +++ b/resource-aggregate/events/resourceLinksSnapshotTaken.go @@ -58,6 +58,10 @@ func (e *ResourceLinksSnapshotTaken) ServiceID() (string, bool) { return "", false } +func (e *ResourceLinksSnapshotTaken) Types() []string { + return nil +} + func (e *ResourceLinksSnapshotTaken) CloneData(event *ResourceLinksSnapshotTaken) { e.DeviceId = event.GetDeviceId() e.Resources = commands.CloneResourcesMap(event.GetResources()) @@ -89,7 +93,7 @@ func (e *ResourceLinksSnapshotTaken) GetNewPublishedLinks(pub *ResourceLinksPubl published := make([]*commands.Resource, 0, len(pub.GetResources())) for _, resPub := range pub.GetResources() { - resSnap, ok := e.Resources[resPub.Href] + resSnap, ok := e.GetResources()[resPub.GetHref()] if !ok || !EqualResource(resPub, resSnap) { published = append(published, resPub) } @@ -226,7 +230,7 @@ func (e *ResourceLinksSnapshotTakenForCommand) HandleCommand(ctx context.Context if newVersion == 0 { return nil, status.Errorf(codes.NotFound, errInvalidVersion) } - if req.CommandMetadata == nil { + if req.GetCommandMetadata() == nil { return nil, status.Errorf(codes.InvalidArgument, errInvalidCommandMetadata) } diff --git a/resource-aggregate/events/resourceLinksSnapshotTaken_test.go b/resource-aggregate/events/resourceLinksSnapshotTaken_test.go index 749eb4353..e049d4ad7 100644 --- a/resource-aggregate/events/resourceLinksSnapshotTaken_test.go +++ b/resource-aggregate/events/resourceLinksSnapshotTaken_test.go @@ -30,8 +30,8 @@ func TestResourceLinksSnapshotTakenGetNewPublishedLinks(t *testing.T) { } res1Upd := commands.Resource{ - Href: res.Href, - DeviceId: res.Href + "-upd", + Href: res.GetHref(), + DeviceId: res.GetHref() + "-upd", } tests := []struct { @@ -66,7 +66,7 @@ func TestResourceLinksSnapshotTakenGetNewPublishedLinks(t *testing.T) { name: "Identical", fields: fields{ Resources: map[string]*commands.Resource{ - res.Href: &res, + res.GetHref(): &res, }, }, args: args{ @@ -92,7 +92,7 @@ func TestResourceLinksSnapshotTakenGetNewPublishedLinks(t *testing.T) { name: "New published resource (2)", fields: fields{ Resources: map[string]*commands.Resource{ - res.Href: &res, + res.GetHref(): &res, }, }, args: args{ @@ -106,8 +106,8 @@ func TestResourceLinksSnapshotTakenGetNewPublishedLinks(t *testing.T) { name: "Updated resource", fields: fields{ Resources: map[string]*commands.Resource{ - res.Href: &res, - resHref.Href: &resHref, + res.GetHref(): &res, + resHref.GetHref(): &resHref, }, }, args: args{ @@ -369,7 +369,7 @@ func TestResourceLinksSnapshotTakenHandleEventResourceLinksUnpublished(t *testin Hrefs: tt.args.hrefs, }) if len(tt.want) == 0 { - require.Len(t, got, 0) + require.Empty(t, got) return } sort.Strings(tt.want) diff --git a/resource-aggregate/events/resourceLinksUnpublished.go b/resource-aggregate/events/resourceLinksUnpublished.go index 52e4a0379..2ca78c775 100644 --- a/resource-aggregate/events/resourceLinksUnpublished.go +++ b/resource-aggregate/events/resourceLinksUnpublished.go @@ -51,6 +51,10 @@ func (e *ResourceLinksUnpublished) ServiceID() (string, bool) { return "", false } +func (e *ResourceLinksUnpublished) Types() []string { + return nil +} + func (e *ResourceLinksUnpublished) CopyData(event *ResourceLinksUnpublished) { e.Hrefs = event.GetHrefs() e.DeviceId = event.GetDeviceId() diff --git a/resource-aggregate/events/resourceRetrievePending.go b/resource-aggregate/events/resourceRetrievePending.go index 73e5ccd87..fc2821bcf 100644 --- a/resource-aggregate/events/resourceRetrievePending.go +++ b/resource-aggregate/events/resourceRetrievePending.go @@ -50,6 +50,10 @@ func (e *ResourceRetrievePending) ServiceID() (string, bool) { return "", false } +func (e *ResourceRetrievePending) Types() []string { + return e.GetResourceTypes() +} + func (e *ResourceRetrievePending) CopyData(event *ResourceRetrievePending) { e.ResourceId = event.GetResourceId() e.ResourceInterface = event.GetResourceInterface() @@ -57,6 +61,7 @@ func (e *ResourceRetrievePending) CopyData(event *ResourceRetrievePending) { e.EventMetadata = event.GetEventMetadata() e.ValidUntil = event.GetValidUntil() e.OpenTelemetryCarrier = event.GetOpenTelemetryCarrier() + e.ResourceTypes = event.GetResourceTypes() } func (e *ResourceRetrievePending) CheckInitialized() bool { diff --git a/resource-aggregate/events/resourceRetrievePending_test.go b/resource-aggregate/events/resourceRetrievePending_test.go index 0c9b56dcc..356519e09 100644 --- a/resource-aggregate/events/resourceRetrievePending_test.go +++ b/resource-aggregate/events/resourceRetrievePending_test.go @@ -25,9 +25,10 @@ var testEventResourceRetrievePending events.ResourceRetrievePending = events.Res ConnectionId: "con1", Sequence: 1, }, + ResourceTypes: []string{"type1", "type2"}, } -func TestResourceRetrievePending_CopyData(t *testing.T) { +func TestResourceRetrievePendingCopyData(t *testing.T) { type args struct { event *events.ResourceRetrievePending } diff --git a/resource-aggregate/events/resourceRetrieved.go b/resource-aggregate/events/resourceRetrieved.go index e1b539df9..f84e4639c 100644 --- a/resource-aggregate/events/resourceRetrieved.go +++ b/resource-aggregate/events/resourceRetrieved.go @@ -51,6 +51,10 @@ func (e *ResourceRetrieved) ServiceID() (string, bool) { return "", false } +func (e *ResourceRetrieved) Types() []string { + return e.GetResourceTypes() +} + func (e *ResourceRetrieved) CopyData(event *ResourceRetrieved) { e.ResourceId = event.GetResourceId() e.Content = event.GetContent() @@ -58,6 +62,7 @@ func (e *ResourceRetrieved) CopyData(event *ResourceRetrieved) { e.EventMetadata = event.GetEventMetadata() e.Status = event.GetStatus() e.OpenTelemetryCarrier = event.GetOpenTelemetryCarrier() + e.ResourceTypes = event.GetResourceTypes() } func (e *ResourceRetrieved) CheckInitialized() bool { diff --git a/resource-aggregate/events/resourceRetrieved_test.go b/resource-aggregate/events/resourceRetrieved_test.go index b86d62d79..2d175d992 100644 --- a/resource-aggregate/events/resourceRetrieved_test.go +++ b/resource-aggregate/events/resourceRetrieved_test.go @@ -30,10 +30,11 @@ var testEventResourceRetrieved events.ResourceRetrieved = events.ResourceRetriev ConnectionId: "con1", Sequence: 1, }, - Status: commands.Status_ACCEPTED, + Status: commands.Status_ACCEPTED, + ResourceTypes: []string{"type1", "type2"}, } -func TestResourceRetrieved_CopyData(t *testing.T) { +func TestResourceRetrievedCopyData(t *testing.T) { type args struct { event *events.ResourceRetrieved } diff --git a/resource-aggregate/events/resourceStateSnapshotTaken.go b/resource-aggregate/events/resourceStateSnapshotTaken.go index 14996d6a1..1fb060e94 100644 --- a/resource-aggregate/events/resourceStateSnapshotTaken.go +++ b/resource-aggregate/events/resourceStateSnapshotTaken.go @@ -66,6 +66,10 @@ func (e *ResourceStateSnapshotTaken) ServiceID() (string, bool) { return "", false } +func (e *ResourceStateSnapshotTaken) Types() []string { + return e.GetResourceTypes() +} + func (e *ResourceStateSnapshotTaken) CopyData(event *ResourceStateSnapshotTaken) { e.ResourceId = event.GetResourceId() e.LatestResourceChange = event.GetLatestResourceChange() @@ -75,6 +79,7 @@ func (e *ResourceStateSnapshotTaken) CopyData(event *ResourceStateSnapshotTaken) e.ResourceDeletePendings = event.GetResourceDeletePendings() e.AuditContext = event.GetAuditContext() e.EventMetadata = event.GetEventMetadata() + e.ResourceTypes = event.GetResourceTypes() } func (e *ResourceStateSnapshotTaken) CheckInitialized() bool { @@ -155,9 +160,17 @@ func (e *ResourceStateSnapshotTaken) handleEventResourceCreatePending(createPend e.EventMetadata = createPending.GetEventMetadata() e.ResourceCreatePendings = append(e.ResourceCreatePendings, createPending) e.AuditContext = createPending.GetAuditContext() + e.setResourceTypes(createPending.GetResourceTypes()) return nil } +func (e *ResourceStateSnapshotTaken) setResourceTypes(resourceTypes []string) { + if len(resourceTypes) == 0 { + return + } + e.ResourceTypes = resourceTypes +} + func (e *ResourceStateSnapshotTaken) handleEventResourceUpdatePending(updatePending *ResourceUpdatePending) error { now := time.Now() if ok := e.processValidUntil(updatePending, now); !ok { @@ -171,6 +184,7 @@ func (e *ResourceStateSnapshotTaken) handleEventResourceUpdatePending(updatePend e.EventMetadata = updatePending.GetEventMetadata() e.ResourceUpdatePendings = append(e.ResourceUpdatePendings, updatePending) e.AuditContext = updatePending.GetAuditContext() + e.setResourceTypes(updatePending.GetResourceTypes()) return nil } @@ -187,6 +201,7 @@ func (e *ResourceStateSnapshotTaken) handleEventResourceRetrievePending(retrieve e.EventMetadata = retrievePending.GetEventMetadata() e.ResourceRetrievePendings = append(e.ResourceRetrievePendings, retrievePending) e.AuditContext = retrievePending.GetAuditContext() + e.setResourceTypes(retrievePending.GetResourceTypes()) return nil } @@ -203,6 +218,7 @@ func (e *ResourceStateSnapshotTaken) handleEventResourceDeletePending(deletePend e.EventMetadata = deletePending.GetEventMetadata() e.ResourceDeletePendings = append(e.ResourceDeletePendings, deletePending) e.AuditContext = deletePending.GetAuditContext() + e.setResourceTypes(deletePending.GetResourceTypes()) return nil } @@ -212,7 +228,8 @@ func RemoveIndex(s []int, index int) []int { func (e *ResourceStateSnapshotTaken) handleEventResourceCreated(created *ResourceCreated) error { index := -1 - for i, event := range e.GetResourceCreatePendings() { + resourceCreatePendings := e.GetResourceCreatePendings() + for i, event := range resourceCreatePendings { if event.GetAuditContext().GetCorrelationId() == created.GetAuditContext().GetCorrelationId() { index = i break @@ -223,14 +240,17 @@ func (e *ResourceStateSnapshotTaken) handleEventResourceCreated(created *Resourc } e.ResourceId = created.GetResourceId() e.EventMetadata = created.GetEventMetadata() - e.ResourceCreatePendings = append(e.ResourceCreatePendings[:index], e.ResourceCreatePendings[index+1:]...) + resourceCreatePendings = append(resourceCreatePendings[:index], resourceCreatePendings[index+1:]...) + e.ResourceCreatePendings = resourceCreatePendings e.AuditContext = created.GetAuditContext() + e.setResourceTypes(created.GetResourceTypes()) return nil } func (e *ResourceStateSnapshotTaken) handleEventResourceUpdated(updated *ResourceUpdated) error { index := -1 - for i, event := range e.GetResourceUpdatePendings() { + resourceUpdatePendings := e.GetResourceUpdatePendings() + for i, event := range resourceUpdatePendings { if event.GetAuditContext().GetCorrelationId() == updated.GetAuditContext().GetCorrelationId() { index = i break @@ -241,14 +261,17 @@ func (e *ResourceStateSnapshotTaken) handleEventResourceUpdated(updated *Resourc } e.ResourceId = updated.GetResourceId() e.EventMetadata = updated.GetEventMetadata() - e.ResourceUpdatePendings = append(e.ResourceUpdatePendings[:index], e.ResourceUpdatePendings[index+1:]...) + resourceUpdatePendings = append(resourceUpdatePendings[:index], resourceUpdatePendings[index+1:]...) + e.ResourceUpdatePendings = resourceUpdatePendings e.AuditContext = updated.GetAuditContext() + e.setResourceTypes(updated.GetResourceTypes()) return nil } func (e *ResourceStateSnapshotTaken) handleEventResourceRetrieved(retrieved *ResourceRetrieved) error { index := -1 - for i, event := range e.GetResourceRetrievePendings() { + resourceRetrievePendings := e.GetResourceRetrievePendings() + for i, event := range resourceRetrievePendings { if event.GetAuditContext().GetCorrelationId() == retrieved.GetAuditContext().GetCorrelationId() { index = i break @@ -259,8 +282,10 @@ func (e *ResourceStateSnapshotTaken) handleEventResourceRetrieved(retrieved *Res } e.ResourceId = retrieved.GetResourceId() e.EventMetadata = retrieved.GetEventMetadata() - e.ResourceRetrievePendings = append(e.ResourceRetrievePendings[:index], e.ResourceRetrievePendings[index+1:]...) + resourceRetrievePendings = append(resourceRetrievePendings[:index], resourceRetrievePendings[index+1:]...) + e.ResourceRetrievePendings = resourceRetrievePendings e.AuditContext = retrieved.GetAuditContext() + e.setResourceTypes(retrieved.GetResourceTypes()) return nil } @@ -281,6 +306,7 @@ func (e *ResourceStateSnapshotTaken) handleEventResourceChanged(changed *Resourc e.EventMetadata = changed.GetEventMetadata() e.LatestResourceChange = changed e.AuditContext = changed.GetAuditContext() + e.setResourceTypes(changed.GetResourceTypes()) return true } return false @@ -294,7 +320,8 @@ func (e *ResourceStateSnapshotTaken) handleEventResourceDeleted(deleted *Resourc e.ResourceUpdatePendings = nil } else { index := -1 - for i, event := range e.GetResourceDeletePendings() { + resourceDeletePendings := e.GetResourceDeletePendings() + for i, event := range resourceDeletePendings { if event.GetAuditContext().GetCorrelationId() == deleted.GetAuditContext().GetCorrelationId() { index = i break @@ -303,11 +330,13 @@ func (e *ResourceStateSnapshotTaken) handleEventResourceDeleted(deleted *Resourc if index < 0 { return status.Errorf(codes.InvalidArgument, "cannot find resource delete pending event with correlationId('%v')", deleted.GetAuditContext().GetCorrelationId()) } - e.ResourceDeletePendings = append(e.ResourceDeletePendings[:index], e.ResourceDeletePendings[index+1:]...) + resourceDeletePendings = append(resourceDeletePendings[:index], resourceDeletePendings[index+1:]...) + e.ResourceDeletePendings = resourceDeletePendings } e.ResourceId = deleted.GetResourceId() e.EventMetadata = deleted.GetEventMetadata() e.AuditContext = deleted.GetAuditContext() + e.setResourceTypes(deleted.GetResourceTypes()) return nil } @@ -315,76 +344,84 @@ func (e *ResourceStateSnapshotTaken) handleEventResourceStateSnapshotTaken(snaps e.CopyData(snapshot) } +//nolint:gocyclo +func (e *ResourceStateSnapshotTaken) handleByEvent(eu eventstore.EventUnmarshaler) error { + if eu.EventType() == "" { + return status.Errorf(codes.Internal, "cannot determine type of event") + } + switch eu.EventType() { + case (&ResourceStateSnapshotTaken{}).EventType(): + var s ResourceStateSnapshotTaken + if err := eu.Unmarshal(&s); err != nil { + return status.Errorf(codes.Internal, "%v", err) + } + e.handleEventResourceStateSnapshotTaken(&s) + case (&ResourceUpdatePending{}).EventType(): + var s ResourceUpdatePending + if err := eu.Unmarshal(&s); err != nil { + return status.Errorf(codes.Internal, "%v", err) + } + _ = e.handleEventResourceUpdatePending(&s) + case (&ResourceUpdated{}).EventType(): + var s ResourceUpdated + if err := eu.Unmarshal(&s); err != nil { + return status.Errorf(codes.Internal, "%v", err) + } + _ = e.handleEventResourceUpdated(&s) + case (&ResourceCreatePending{}).EventType(): + var s ResourceCreatePending + if err := eu.Unmarshal(&s); err != nil { + return status.Errorf(codes.Internal, "%v", err) + } + _ = e.handleEventResourceCreatePending(&s) + case (&ResourceCreated{}).EventType(): + var s ResourceCreated + if err := eu.Unmarshal(&s); err != nil { + return status.Errorf(codes.Internal, "%v", err) + } + _ = e.handleEventResourceCreated(&s) + case (&ResourceChanged{}).EventType(): + var s ResourceChanged + if err := eu.Unmarshal(&s); err != nil { + return status.Errorf(codes.Internal, "%v", err) + } + _ = e.handleEventResourceChanged(&s) + case (&ResourceDeleted{}).EventType(): + var s ResourceDeleted + if err := eu.Unmarshal(&s); err != nil { + return status.Errorf(codes.Internal, "%v", err) + } + _ = e.handleEventResourceDeleted(&s) + case (&ResourceDeletePending{}).EventType(): + var s ResourceDeletePending + if err := eu.Unmarshal(&s); err != nil { + return status.Errorf(codes.Internal, "%v", err) + } + _ = e.handleEventResourceDeletePending(&s) + case (&ResourceRetrieved{}).EventType(): + var s ResourceRetrieved + if err := eu.Unmarshal(&s); err != nil { + return status.Errorf(codes.Internal, "%v", err) + } + _ = e.handleEventResourceRetrieved(&s) + case (&ResourceRetrievePending{}).EventType(): + var s ResourceRetrievePending + if err := eu.Unmarshal(&s); err != nil { + return status.Errorf(codes.Internal, "%v", err) + } + _ = e.handleEventResourceRetrievePending(&s) + } + return nil +} + func (e *ResourceStateSnapshotTaken) Handle(ctx context.Context, iter eventstore.Iter) error { for { eu, ok := iter.Next(ctx) if !ok { break } - if eu.EventType() == "" { - return status.Errorf(codes.Internal, "cannot determine type of event") - } - switch eu.EventType() { - case (&ResourceStateSnapshotTaken{}).EventType(): - var s ResourceStateSnapshotTaken - if err := eu.Unmarshal(&s); err != nil { - return status.Errorf(codes.Internal, "%v", err) - } - e.handleEventResourceStateSnapshotTaken(&s) - case (&ResourceUpdatePending{}).EventType(): - var s ResourceUpdatePending - if err := eu.Unmarshal(&s); err != nil { - return status.Errorf(codes.Internal, "%v", err) - } - _ = e.handleEventResourceUpdatePending(&s) - case (&ResourceUpdated{}).EventType(): - var s ResourceUpdated - if err := eu.Unmarshal(&s); err != nil { - return status.Errorf(codes.Internal, "%v", err) - } - _ = e.handleEventResourceUpdated(&s) - case (&ResourceCreatePending{}).EventType(): - var s ResourceCreatePending - if err := eu.Unmarshal(&s); err != nil { - return status.Errorf(codes.Internal, "%v", err) - } - _ = e.handleEventResourceCreatePending(&s) - case (&ResourceCreated{}).EventType(): - var s ResourceCreated - if err := eu.Unmarshal(&s); err != nil { - return status.Errorf(codes.Internal, "%v", err) - } - _ = e.handleEventResourceCreated(&s) - case (&ResourceChanged{}).EventType(): - var s ResourceChanged - if err := eu.Unmarshal(&s); err != nil { - return status.Errorf(codes.Internal, "%v", err) - } - _ = e.handleEventResourceChanged(&s) - case (&ResourceDeleted{}).EventType(): - var s ResourceDeleted - if err := eu.Unmarshal(&s); err != nil { - return status.Errorf(codes.Internal, "%v", err) - } - _ = e.handleEventResourceDeleted(&s) - case (&ResourceDeletePending{}).EventType(): - var s ResourceDeletePending - if err := eu.Unmarshal(&s); err != nil { - return status.Errorf(codes.Internal, "%v", err) - } - _ = e.handleEventResourceDeletePending(&s) - case (&ResourceRetrieved{}).EventType(): - var s ResourceRetrieved - if err := eu.Unmarshal(&s); err != nil { - return status.Errorf(codes.Internal, "%v", err) - } - _ = e.handleEventResourceRetrieved(&s) - case (&ResourceRetrievePending{}).EventType(): - var s ResourceRetrievePending - if err := eu.Unmarshal(&s); err != nil { - return status.Errorf(codes.Internal, "%v", err) - } - _ = e.handleEventResourceRetrievePending(&s) + if err := e.handleByEvent(eu); err != nil { + return err } } return iter.Err() @@ -407,15 +444,11 @@ func convertContent(content *commands.Content, supportedContentType string) (new encode = cbor.Encode coapContentFormat = int32(message.AppCBOR) case message.AppOcfCbor.String(): - if encode == nil { - encode = cbor.Encode - coapContentFormat = int32(message.AppOcfCbor) - } + encode = cbor.Encode + coapContentFormat = int32(message.AppOcfCbor) case message.AppJSON.String(): - if encode == nil { - encode = json.Encode - coapContentFormat = int32(message.AppJSON) - } + encode = json.Encode + coapContentFormat = int32(message.AppJSON) } if encode == nil { @@ -450,7 +483,7 @@ func convertContent(content *commands.Content, supportedContentType string) (new } func (e *ResourceStateSnapshotTakenForCommand) confirmResourceUpdateRequest(ctx context.Context, req *commands.ConfirmResourceUpdateRequest, newVersion uint64) ([]eventstore.Event, error) { - if req.CommandMetadata == nil { + if req.GetCommandMetadata() == nil { return nil, status.Errorf(codes.InvalidArgument, errInvalidCommandMetadata) } @@ -463,6 +496,7 @@ func (e *ResourceStateSnapshotTakenForCommand) confirmResourceUpdateRequest(ctx Content: req.GetContent(), Status: req.GetStatus(), OpenTelemetryCarrier: propagation.TraceFromCtx(ctx), + ResourceTypes: e.resolveResourceTypes(req.GetResourceId().GetHref(), nil), } if err := e.handleEventResourceUpdated(&rc); err != nil { return nil, err @@ -485,6 +519,7 @@ func (e *ResourceStateSnapshotTakenForCommand) confirmResourceRetrieveRequest(ct Status: req.GetStatus(), OpenTelemetryCarrier: propagation.TraceFromCtx(ctx), Etag: req.GetEtag(), + ResourceTypes: e.resolveResourceTypes(req.GetResourceId().GetHref(), nil), } if err := e.handleEventResourceRetrieved(&rc); err != nil { return nil, err @@ -506,6 +541,7 @@ func (e *ResourceStateSnapshotTakenForCommand) confirmResourceDeleteRequest(ctx Content: req.GetContent(), Status: req.GetStatus(), OpenTelemetryCarrier: propagation.TraceFromCtx(ctx), + ResourceTypes: e.resolveResourceTypes(req.GetResourceId().GetHref(), nil), } if err := e.handleEventResourceDeleted(&rc); err != nil { return nil, err @@ -527,7 +563,9 @@ func (e *ResourceStateSnapshotTakenForCommand) confirmResourceCreateRequest(ctx Content: req.GetContent(), Status: req.GetStatus(), OpenTelemetryCarrier: propagation.TraceFromCtx(ctx), + ResourceTypes: e.resolveResourceTypes(req.GetResourceId().GetHref(), nil), } + if err := e.handleEventResourceCreated(&rc); err != nil { return nil, err } @@ -633,7 +671,7 @@ func (e *ResourceStateSnapshotTakenForCommand) CancelPendingCommandsRequest(ctx } func (e *ResourceStateSnapshotTakenForCommand) handleNotifyResourceChangedRequest(ctx context.Context, req *commands.NotifyResourceChangedRequest, newVersion uint64) ([]eventstore.Event, error) { - if req.CommandMetadata == nil { + if req.GetCommandMetadata() == nil { return nil, status.Errorf(codes.InvalidArgument, errInvalidCommandMetadata) } @@ -648,6 +686,7 @@ func (e *ResourceStateSnapshotTakenForCommand) handleNotifyResourceChangedReques Status: req.GetStatus(), OpenTelemetryCarrier: propagation.TraceFromCtx(ctx), Etag: req.GetEtag(), + ResourceTypes: e.resolveResourceTypes(req.GetResourceId().GetHref(), req.GetResourceTypes()), } if e.handleEventResourceChanged(&rc) { @@ -676,6 +715,7 @@ func (e *ResourceStateSnapshotTakenForCommand) handleUpdateResourceRequest(ctx c Content: content, ValidUntil: timeToLive2ValidUntil(req.GetTimeToLive()), OpenTelemetryCarrier: propagation.TraceFromCtx(ctx), + ResourceTypes: e.resolveResourceTypes(req.GetResourceId().GetHref(), nil), } if err = e.handleEventResourceUpdatePending(&rc); err != nil { @@ -700,6 +740,7 @@ func (e *ResourceStateSnapshotTakenForCommand) handleRetrieveResourceRequest(ctx ValidUntil: timeToLive2ValidUntil(req.GetTimeToLive()), OpenTelemetryCarrier: propagation.TraceFromCtx(ctx), Etag: req.GetEtag(), + ResourceTypes: e.resolveResourceTypes(req.GetResourceId().GetHref(), nil), } if err := e.handleEventResourceRetrievePending(&rc); err != nil { @@ -723,6 +764,7 @@ func (e *ResourceStateSnapshotTakenForCommand) handleDeleteResourceRequest(ctx c ValidUntil: timeToLive2ValidUntil(req.GetTimeToLive()), ResourceInterface: req.GetResourceInterface(), OpenTelemetryCarrier: propagation.TraceFromCtx(ctx), + ResourceTypes: e.resolveResourceTypes(req.GetResourceId().GetHref(), nil), } if err := e.handleEventResourceDeletePending(&rc); err != nil { @@ -731,6 +773,29 @@ func (e *ResourceStateSnapshotTakenForCommand) handleDeleteResourceRequest(ctx c return []eventstore.Event{&rc}, nil } +func (e *ResourceStateSnapshotTakenForCommand) resolveResourceTypes(href string, resourceTypes []string) []string { + if len(resourceTypes) > 0 { + // resourceTypes from command has higher priority + return resourceTypes + } + if e.resourceLinks == nil { + // if no resourceLinks, return resourceTypes from snapshot + return e.GetResourceTypes() + } + resources := e.resourceLinks.GetResources() + if len(resources) == 0 { + // if no resourceLinks, return resourceTypes from snapshot + return e.GetResourceTypes() + } + link, ok := e.resourceLinks.GetResources()[href] + if !ok { + // if resourceLinks doesn't contain resource, return resourceTypes from snapshot + return e.GetResourceTypes() + } + // return resourceTypes from link + return link.GetResourceTypes() +} + func (e *ResourceStateSnapshotTakenForCommand) handleCreateResourceRequest(ctx context.Context, req *commands.CreateResourceRequest, newVersion uint64) ([]eventstore.Event, error) { if req.GetCommandMetadata() == nil { return nil, status.Errorf(codes.InvalidArgument, errInvalidCommandMetadata) @@ -749,6 +814,7 @@ func (e *ResourceStateSnapshotTakenForCommand) handleCreateResourceRequest(ctx c EventMetadata: em, ValidUntil: timeToLive2ValidUntil(req.GetTimeToLive()), OpenTelemetryCarrier: propagation.TraceFromCtx(ctx), + ResourceTypes: e.resolveResourceTypes(req.GetResourceId().GetHref(), nil), } if err := e.handleEventResourceCreatePending(&rc); err != nil { @@ -799,22 +865,25 @@ func (e *ResourceStateSnapshotTaken) TakeSnapshot(version uint64) (eventstore.Ev ResourceRetrievePendings: e.GetResourceRetrievePendings(), ResourceDeletePendings: e.GetResourceDeletePendings(), AuditContext: e.GetAuditContext(), + ResourceTypes: e.GetResourceTypes(), }, true } type ResourceStateSnapshotTakenForCommand struct { - owner string - hubID string - userID string + owner string + hubID string + userID string + resourceLinks *ResourceLinksSnapshotTakenForCommand *ResourceStateSnapshotTaken } -func NewResourceStateSnapshotTakenForCommand(userID string, owner string, hubID string) *ResourceStateSnapshotTakenForCommand { +func NewResourceStateSnapshotTakenForCommand(userID string, owner string, hubID string, resourceLinks *ResourceLinksSnapshotTakenForCommand) *ResourceStateSnapshotTakenForCommand { return &ResourceStateSnapshotTakenForCommand{ ResourceStateSnapshotTaken: NewResourceStateSnapshotTaken(), userID: userID, owner: owner, hubID: hubID, + resourceLinks: resourceLinks, } } diff --git a/resource-aggregate/events/resourceStateSnapshotTaken_test.go b/resource-aggregate/events/resourceStateSnapshotTaken_test.go index 383d3f343..18af0389c 100644 --- a/resource-aggregate/events/resourceStateSnapshotTaken_test.go +++ b/resource-aggregate/events/resourceStateSnapshotTaken_test.go @@ -39,7 +39,41 @@ func (i *iterator) Err() error { return nil } -func TestResourceStateSnapshotTaken_Handle(t *testing.T) { +func TestResourceStateSnapshotTakenResourceTypes(t *testing.T) { + const ( + href = "/a" + deviceID = "a" + hubID = "hubID" + userID = "userID" + ) + resourceTypes := []string{"type1", "type2"} + + e := events.NewResourceStateSnapshotTaken() + require.Empty(t, e.Types()) + err := e.Handle(context.TODO(), newIterator([]eventstore.EventUnmarshaler{test.MakeResourceChangedEvent(commands.NewResourceID(deviceID, href), &commands.Content{}, events.MakeEventMeta("", 0, 0, hubID), commands.NewAuditContext(userID, "0", userID), resourceTypes)})) + require.NoError(t, err) + require.Equal(t, resourceTypes, e.Types()) + nextEvents := newIterator([]eventstore.EventUnmarshaler{ + test.MakeResourceCreatePending(commands.NewResourceID(deviceID, href), &commands.Content{}, events.MakeEventMeta("", 0, 1, hubID), commands.NewAuditContext(userID, "0", userID), time.Now().Add(-time.Second), resourceTypes), + test.MakeResourceCreated(commands.NewResourceID(deviceID, href), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 2, hubID), commands.NewAuditContext(userID, "0", userID), resourceTypes), + test.MakeResourceRetrievePending(commands.NewResourceID(deviceID, href), "", events.MakeEventMeta("", 0, 3, hubID), commands.NewAuditContext(userID, "1", userID), time.Now().Add(-time.Second), resourceTypes), + test.MakeResourceRetrieved(commands.NewResourceID(deviceID, href), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 4, hubID), commands.NewAuditContext(userID, "1", userID), resourceTypes), + test.MakeResourceUpdatePending(commands.NewResourceID(deviceID, href), &commands.Content{}, events.MakeEventMeta("", 0, 5, hubID), commands.NewAuditContext(userID, "2", userID), time.Now().Add(-time.Second), resourceTypes), + test.MakeResourceUpdated(commands.NewResourceID(deviceID, href), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 6, hubID), commands.NewAuditContext(userID, "2", userID), resourceTypes), + test.MakeResourceDeletePending(commands.NewResourceID(deviceID, href), events.MakeEventMeta("", 0, 7, hubID), commands.NewAuditContext(userID, "3", userID), time.Now().Add(-time.Second), resourceTypes), + test.MakeResourceDeleted(commands.NewResourceID(deviceID, href), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 8, hubID), commands.NewAuditContext(userID, "3", userID), resourceTypes), + }) + err = e.Handle(context.TODO(), nextEvents) + require.NoError(t, err) + require.Equal(t, resourceTypes, e.Types()) + resourceTypes = append(resourceTypes, "type3") + err = e.Handle(context.TODO(), newIterator([]eventstore.EventUnmarshaler{test.MakeResourceChangedEvent(commands.NewResourceID(deviceID, href), &commands.Content{}, events.MakeEventMeta("", 1, 9, hubID), commands.NewAuditContext(userID, "0", userID), resourceTypes)})) + require.NoError(t, err) + require.Equal(t, resourceTypes, e.Types()) +} + +func TestResourceStateSnapshotTakenHandle(t *testing.T) { + resourceTypes := []string{"type1", "type2"} type args struct { events *iterator } @@ -52,8 +86,8 @@ func TestResourceStateSnapshotTaken_Handle(t *testing.T) { name: "createPending, created", args: args{ events: newIterator([]eventstore.EventUnmarshaler{ - test.MakeResourceCreatePending(commands.NewResourceID("a", "/a"), &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "0", "userID"), time.Now().Add(-time.Second)), - test.MakeResourceCreated(commands.NewResourceID("a", "/a"), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "0", "userID")), + test.MakeResourceCreatePending(commands.NewResourceID("a", "/a"), &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "0", "userID"), time.Now().Add(-time.Second), resourceTypes), + test.MakeResourceCreated(commands.NewResourceID("a", "/a"), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "0", "userID"), resourceTypes), }), }, }, @@ -61,8 +95,8 @@ func TestResourceStateSnapshotTaken_Handle(t *testing.T) { name: "retrievePending, retrieved", args: args{ events: newIterator([]eventstore.EventUnmarshaler{ - test.MakeResourceRetrievePending(commands.NewResourceID("a", "/a"), "", events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "1", "userID"), time.Now().Add(-time.Second)), - test.MakeResourceRetrieved(commands.NewResourceID("a", "/a"), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "1", "userID")), + test.MakeResourceRetrievePending(commands.NewResourceID("a", "/a"), "", events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "1", "userID"), time.Now().Add(-time.Second), resourceTypes), + test.MakeResourceRetrieved(commands.NewResourceID("a", "/a"), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "1", "userID"), resourceTypes), }), }, }, @@ -70,17 +104,17 @@ func TestResourceStateSnapshotTaken_Handle(t *testing.T) { name: "updatePending, updated", args: args{ events: newIterator([]eventstore.EventUnmarshaler{ - test.MakeResourceUpdatePending(commands.NewResourceID("a", "/a"), &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "2", "userID"), time.Now().Add(-time.Second)), - test.MakeResourceUpdated(commands.NewResourceID("a", "/a"), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "2", "userID")), + test.MakeResourceUpdatePending(commands.NewResourceID("a", "/a"), &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "2", "userID"), time.Now().Add(-time.Second), resourceTypes), + test.MakeResourceUpdated(commands.NewResourceID("a", "/a"), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "2", "userID"), resourceTypes), }), }, }, { - name: "retrievePending, retrieved", + name: "deletePending, deleted", args: args{ events: newIterator([]eventstore.EventUnmarshaler{ - test.MakeResourceDeletePending(commands.NewResourceID("a", "/a"), events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "3", "userID"), time.Now().Add(-time.Second)), - test.MakeResourceDeleted(commands.NewResourceID("a", "/a"), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "3", "userID")), + test.MakeResourceDeletePending(commands.NewResourceID("a", "/a"), events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "3", "userID"), time.Now().Add(-time.Second), resourceTypes), + test.MakeResourceDeleted(commands.NewResourceID("a", "/a"), commands.Status_OK, &commands.Content{}, events.MakeEventMeta("", 0, 0, "hubID"), commands.NewAuditContext("userID", "3", "userID"), resourceTypes), }), }, }, @@ -117,21 +151,21 @@ func TestEqual(t *testing.T) { ContentType: "text", CoapContentFormat: int32(message.TextPlain), }, - AuditContext: res.AuditContext, - Status: res.Status, + AuditContext: res.GetAuditContext(), + Status: res.GetStatus(), } resWithChangedAuditContext := events.ResourceChanged{ - Content: res.Content, + Content: res.GetContent(), AuditContext: &commands.AuditContext{ UserId: "502", }, - Status: res.Status, + Status: res.GetStatus(), } resWithChangedStatus := events.ResourceChanged{ - Content: res.Content, - AuditContext: res.AuditContext, + Content: res.GetContent(), + AuditContext: res.GetAuditContext(), Status: commands.Status_ERROR, } @@ -195,7 +229,8 @@ var testEventResourceStateSnapshotTaken events.ResourceStateSnapshotTaken = even DeviceId: "devLatest", Href: "/devLatest", }, - Content: &commands.Content{}, + Content: &commands.Content{}, + ResourceTypes: []string{"type1", "type2"}, }, ResourceCreatePendings: []*events.ResourceCreatePending{ { @@ -203,6 +238,7 @@ var testEventResourceStateSnapshotTaken events.ResourceStateSnapshotTaken = even DeviceId: "devCreate", Href: "/devCreate", }, + ResourceTypes: []string{"type1", "type2"}, }, }, ResourceRetrievePendings: []*events.ResourceRetrievePending{ @@ -211,6 +247,7 @@ var testEventResourceStateSnapshotTaken events.ResourceStateSnapshotTaken = even DeviceId: "devRetrieve", Href: "/devRetrieve", }, + ResourceTypes: []string{"type1", "type2"}, }, }, ResourceUpdatePendings: []*events.ResourceUpdatePending{ @@ -219,6 +256,7 @@ var testEventResourceStateSnapshotTaken events.ResourceStateSnapshotTaken = even DeviceId: "devUpdate", Href: "/devUpdate", }, + ResourceTypes: []string{"type1", "type2"}, }, }, ResourceDeletePendings: []*events.ResourceDeletePending{ @@ -227,6 +265,7 @@ var testEventResourceStateSnapshotTaken events.ResourceStateSnapshotTaken = even DeviceId: "devDelete", Href: "/devDelete", }, + ResourceTypes: []string{"type1", "type2"}, }, }, AuditContext: &commands.AuditContext{ @@ -239,9 +278,10 @@ var testEventResourceStateSnapshotTaken events.ResourceStateSnapshotTaken = even ConnectionId: "con1", Sequence: 1, }, + ResourceTypes: []string{"type1", "type2"}, } -func TestResourceStateSnapshotTaken_CopyData(t *testing.T) { +func TestResourceStateSnapshotTakenCopyData(t *testing.T) { type args struct { event *events.ResourceStateSnapshotTaken } diff --git a/resource-aggregate/events/resourceUpdatePending.go b/resource-aggregate/events/resourceUpdatePending.go index 0fdbc5013..45c51e072 100644 --- a/resource-aggregate/events/resourceUpdatePending.go +++ b/resource-aggregate/events/resourceUpdatePending.go @@ -50,6 +50,10 @@ func (e *ResourceUpdatePending) ServiceID() (string, bool) { return "", false } +func (e *ResourceUpdatePending) Types() []string { + return e.GetResourceTypes() +} + func (e *ResourceUpdatePending) CopyData(event *ResourceUpdatePending) { e.ResourceId = event.GetResourceId() e.ResourceInterface = event.GetResourceInterface() @@ -58,6 +62,7 @@ func (e *ResourceUpdatePending) CopyData(event *ResourceUpdatePending) { e.EventMetadata = event.GetEventMetadata() e.ValidUntil = event.GetValidUntil() e.OpenTelemetryCarrier = event.GetOpenTelemetryCarrier() + e.ResourceTypes = event.GetResourceTypes() } func (e *ResourceUpdatePending) CheckInitialized() bool { diff --git a/resource-aggregate/events/resourceUpdatePending_test.go b/resource-aggregate/events/resourceUpdatePending_test.go index 4a823a9f7..9bd0d050e 100644 --- a/resource-aggregate/events/resourceUpdatePending_test.go +++ b/resource-aggregate/events/resourceUpdatePending_test.go @@ -34,9 +34,10 @@ var testEventResourceUpdatePending events.ResourceUpdatePending = events.Resourc ConnectionId: "con1", Sequence: 1, }, + ResourceTypes: []string{"type1", "type2"}, } -func TestResourceUpdatePending_CopyData(t *testing.T) { +func TestResourceUpdatePendingCopyData(t *testing.T) { type args struct { event *events.ResourceUpdatePending } diff --git a/resource-aggregate/events/resourceUpdated.go b/resource-aggregate/events/resourceUpdated.go index 6845923c0..6c7bac5c8 100644 --- a/resource-aggregate/events/resourceUpdated.go +++ b/resource-aggregate/events/resourceUpdated.go @@ -51,6 +51,10 @@ func (e *ResourceUpdated) ServiceID() (string, bool) { return "", false } +func (e *ResourceUpdated) Types() []string { + return e.GetResourceTypes() +} + func (e *ResourceUpdated) CopyData(event *ResourceUpdated) { e.ResourceId = event.GetResourceId() e.Status = event.GetStatus() @@ -58,6 +62,7 @@ func (e *ResourceUpdated) CopyData(event *ResourceUpdated) { e.AuditContext = event.GetAuditContext() e.EventMetadata = event.GetEventMetadata() e.OpenTelemetryCarrier = event.GetOpenTelemetryCarrier() + e.ResourceTypes = event.GetResourceTypes() } func (e *ResourceUpdated) CheckInitialized() bool { diff --git a/resource-aggregate/events/resourceUpdated_test.go b/resource-aggregate/events/resourceUpdated_test.go index e18e8edf1..e0631614c 100644 --- a/resource-aggregate/events/resourceUpdated_test.go +++ b/resource-aggregate/events/resourceUpdated_test.go @@ -31,9 +31,10 @@ var testEventResourceUpdated events.ResourceUpdated = events.ResourceUpdated{ ConnectionId: "con1", Sequence: 1, }, + ResourceTypes: []string{"type1", "type2"}, } -func TestResourceUpdated_CopyData(t *testing.T) { +func TestResourceUpdatedCopyData(t *testing.T) { type args struct { event *events.ResourceUpdated } diff --git a/resource-aggregate/events/serviceMetadataSnapshotTaken.go b/resource-aggregate/events/serviceMetadataSnapshotTaken.go index 8ea150e85..4110973eb 100644 --- a/resource-aggregate/events/serviceMetadataSnapshotTaken.go +++ b/resource-aggregate/events/serviceMetadataSnapshotTaken.go @@ -2,6 +2,7 @@ package events import ( "context" + "errors" "fmt" "sort" "time" @@ -62,6 +63,10 @@ func (d *ServiceMetadataSnapshotTaken) ServiceID() (string, bool) { return "", false } +func (d *ServiceMetadataSnapshotTaken) Types() []string { + return nil +} + func (d *ServiceMetadataSnapshotTaken) CopyData(event *ServiceMetadataSnapshotTaken) { d.ServiceMetadataUpdated = event.GetServiceMetadataUpdated() d.EventMetadata = event.GetEventMetadata() @@ -73,7 +78,7 @@ func (d *ServiceMetadataSnapshotTaken) CheckInitialized() bool { } func (d *ServiceMetadataSnapshotTaken) HandleServiceMetadataUpdated(_ context.Context, upd *ServiceMetadataUpdated) (bool, error) { - if d.ServiceMetadataUpdated.Equal(upd) { + if d.GetServiceMetadataUpdated().Equal(upd) { return false, nil } valid := make(map[string]*ServicesHeartbeat_Heartbeat, len(d.GetServiceMetadataUpdated().GetServicesHeartbeat().GetValid())+len(upd.GetServicesHeartbeat().GetValid())) @@ -322,7 +327,7 @@ func (d *ServiceMetadataSnapshotTaken) confirmExpiredServices(ctx context.Contex d.EventMetadata = em snapshot, ok := d.TakeSnapshot(em.GetVersion()) if !ok { - return nil, fmt.Errorf("cannot take snapshot") + return nil, errors.New("cannot take snapshot") } return []eventstore.Event{snapshot}, nil } diff --git a/resource-aggregate/events/serviceMetadataUpdated.go b/resource-aggregate/events/serviceMetadataUpdated.go index d79755a53..81db2566b 100644 --- a/resource-aggregate/events/serviceMetadataUpdated.go +++ b/resource-aggregate/events/serviceMetadataUpdated.go @@ -51,12 +51,17 @@ func (d *ServiceMetadataUpdated) ServiceID() (string, bool) { return "", false } +func (d *ServiceMetadataUpdated) Types() []string { + return nil +} + func (d *ServiceMetadataUpdated) CopyData(event *ServiceMetadataUpdated) { d.EventMetadata = event.GetEventMetadata() d.OpenTelemetryCarrier = event.GetOpenTelemetryCarrier() - d.ServicesHeartbeat = &ServicesHeartbeat{} - d.ServicesHeartbeat.CopyData(event.GetServicesHeartbeat()) + sh := &ServicesHeartbeat{} + sh.CopyData(event.GetServicesHeartbeat()) + d.ServicesHeartbeat = sh } func (d *ServiceMetadataUpdated) CheckInitialized() bool { diff --git a/resource-aggregate/events/utils.go b/resource-aggregate/events/utils.go index de67bbeb6..6f4a97125 100644 --- a/resource-aggregate/events/utils.go +++ b/resource-aggregate/events/utils.go @@ -18,15 +18,15 @@ func MakeEventMeta(connectionID string, sequence, version uint64, hubID string) } func EqualResource(x, y *commands.Resource) bool { - return x.DeviceId == y.DeviceId && - EqualStringSlice(x.ResourceTypes, y.ResourceTypes) && - EqualStringSlice(x.Interfaces, y.Interfaces) && - x.Anchor == y.Anchor && - x.Title == y.Title && - EqualStringSlice(x.SupportedContentTypes, y.SupportedContentTypes) && - x.ValidUntil == y.ValidUntil && - ((x.Policy == nil && y.Policy == nil) || - (x.Policy != nil && y.Policy != nil && x.Policy.BitFlags == y.Policy.BitFlags)) + return x.GetDeviceId() == y.GetDeviceId() && + EqualStringSlice(x.GetResourceTypes(), y.GetResourceTypes()) && + EqualStringSlice(x.GetInterfaces(), y.GetInterfaces()) && + x.GetAnchor() == y.GetAnchor() && + x.GetTitle() == y.GetTitle() && + EqualStringSlice(x.GetSupportedContentTypes(), y.GetSupportedContentTypes()) && + x.GetValidUntil() == y.GetValidUntil() && + ((x.GetPolicy() == nil && y.GetPolicy() == nil) || + (x.GetPolicy() != nil && y.GetPolicy() != nil && x.GetPolicy().GetBitFlags() == y.GetPolicy().GetBitFlags())) } func EqualStringSlice(x, y []string) bool { diff --git a/resource-aggregate/events/utils_test.go b/resource-aggregate/events/utils_test.go index 6d5a3e625..f9dee92f6 100644 --- a/resource-aggregate/events/utils_test.go +++ b/resource-aggregate/events/utils_test.go @@ -94,8 +94,9 @@ func TestEqualResource(t *testing.T) { resInterfacesNil.Interfaces = nil resInterfaces2 := createResource() - resInterfaces2.Interfaces = make([]string, 1) - copy(resInterfaces2.Interfaces, res.Interfaces) + interfaces := make([]string, 1) + copy(interfaces, res.GetInterfaces()) + resInterfaces2.Interfaces = interfaces resAnchor := createResource() resAnchor.Anchor = "Anchor2" diff --git a/resource-aggregate/pb/commands.proto b/resource-aggregate/pb/commands.proto index dcac3dd94..41bf7b09e 100644 --- a/resource-aggregate/pb/commands.proto +++ b/resource-aggregate/pb/commands.proto @@ -95,6 +95,7 @@ message NotifyResourceChangedRequest { CommandMetadata command_metadata = 3; Status status = 4; bytes etag = 5; + repeated string resource_types = 6; } message NotifyResourceChangedResponse { @@ -443,6 +444,7 @@ message Connection { } Protocol protocol = 5; // application protocol. It need to be set when the status is ONLINE. string service_id = 6; // The service.ID, which identify the device being served, must be set when the status is ONLINE. However, during an OFFLINE event, they will be sed to empty values. + repeated string local_endpoints = 7; // The last local endpoints of the device, and it is set when the status is ONLINE. } //******************************************************************************************************************************************************* // Update Device Metadata - Twin Synchronization State diff --git a/resource-aggregate/pb/events.proto b/resource-aggregate/pb/events.proto index 1cd534e45..080eb74b5 100644 --- a/resource-aggregate/pb/events.proto +++ b/resource-aggregate/pb/events.proto @@ -54,6 +54,7 @@ message ResourceChanged { AuditContext audit_context = 4; EventMetadata event_metadata = 5; bytes etag = 6; // etag of the resource used by twin synchronization + repeated string resource_types = 7; // Open telemetry data propagated to asynchronous events map open_telemetry_carrier = 100; @@ -66,6 +67,7 @@ message ResourceUpdatePending { AuditContext audit_context = 4; EventMetadata event_metadata = 5; int64 valid_until = 6; // unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. + repeated string resource_types = 7; // Open telemetry data propagated to asynchronous events map open_telemetry_carrier = 100; @@ -77,6 +79,7 @@ message ResourceUpdated { Content content = 3; AuditContext audit_context = 4; EventMetadata event_metadata = 5; + repeated string resource_types = 6; // Open telemetry data propagated to asynchronous events map open_telemetry_carrier = 100; @@ -89,6 +92,7 @@ message ResourceRetrievePending { EventMetadata event_metadata = 4; int64 valid_until = 5; // unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. repeated bytes etag = 6; + repeated string resource_types = 7; // Open telemetry data propagated to asynchronous events map open_telemetry_carrier = 100; @@ -101,6 +105,7 @@ message ResourceRetrieved { AuditContext audit_context = 4; EventMetadata event_metadata = 5; bytes etag = 6; + repeated string resource_types = 7; // Open telemetry data propagated to asynchronous events map open_telemetry_carrier = 100; @@ -112,6 +117,7 @@ message ResourceDeletePending { EventMetadata event_metadata = 3; int64 valid_until = 4; // unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. string resource_interface = 5; + repeated string resource_types = 6; // Open telemetry data propagated to asynchronous events map open_telemetry_carrier = 100; @@ -123,6 +129,7 @@ message ResourceDeleted { Content content = 3; AuditContext audit_context = 4; EventMetadata event_metadata = 5; + repeated string resource_types = 6; // Open telemetry data propagated to asynchronous events map open_telemetry_carrier = 100; @@ -134,6 +141,7 @@ message ResourceCreatePending { AuditContext audit_context = 3; EventMetadata event_metadata = 4; int64 valid_until = 5; // unix timestamp in nanoseconds (https://golang.org/pkg/time/#Time.UnixNano) when pending event is considered as expired. 0 means forever. + repeated string resource_types = 6; // Open telemetry data propagated to asynchronous events map open_telemetry_carrier = 100; @@ -145,6 +153,7 @@ message ResourceCreated { Content content = 3; AuditContext audit_context = 4; EventMetadata event_metadata = 5; + repeated string resource_types = 6; // Open telemetry data propagated to asynchronous events map open_telemetry_carrier = 100; @@ -159,6 +168,7 @@ message ResourceStateSnapshotTaken { repeated ResourceDeletePending resource_delete_pendings = 6; // expired events will be removed by creating a new snapshot. AuditContext audit_context = 7; EventMetadata event_metadata = 8; + repeated string resource_types = 9; // Open telemetry data propagated to asynchronous events // map open_telemetry_carrier = 100; diff --git a/resource-aggregate/service/aggregate.go b/resource-aggregate/service/aggregate.go index 63722234a..f25bdad35 100644 --- a/resource-aggregate/service/aggregate.go +++ b/resource-aggregate/service/aggregate.go @@ -21,43 +21,60 @@ type Aggregate struct { eventstore eventstore.EventStore } -func NewResourceStateFactoryModel(userID, owner, hubID string) func(ctx context.Context) (cqrsAggregate.AggregateModel, error) { - return func(ctx context.Context) (cqrsAggregate.AggregateModel, error) { - return events.NewResourceStateSnapshotTakenForCommand(userID, owner, hubID), nil +func NewResourceStateFactoryModel(userID, owner, hubID string) func(context.Context, string, string) (cqrsAggregate.AggregateModel, error) { + resourceLinks := events.NewResourceLinksSnapshotTakenForCommand(userID, owner, hubID) + resourceState := events.NewResourceStateSnapshotTakenForCommand(userID, owner, hubID, resourceLinks) + return func(_ context.Context, groupID string, aggregateID string) (cqrsAggregate.AggregateModel, error) { + resID := commands.NewResourceID(groupID, commands.ResourceLinksHref) + if aggregateID == resID.ToUUID().String() { + return resourceLinks, nil + } + return resourceState, nil } } -func NewResourceLinksFactoryModel(userID, owner, hubID string) func(ctx context.Context) (cqrsAggregate.AggregateModel, error) { - return func(ctx context.Context) (cqrsAggregate.AggregateModel, error) { +func NewResourceLinksFactoryModel(userID, owner, hubID string) func(context.Context, string, string) (cqrsAggregate.AggregateModel, error) { + return func(context.Context, string, string) (cqrsAggregate.AggregateModel, error) { return events.NewResourceLinksSnapshotTakenForCommand(userID, owner, hubID), nil } } -func NewDeviceMetadataFactoryModel(userID, owner, hubID string) func(ctx context.Context) (cqrsAggregate.AggregateModel, error) { - return func(ctx context.Context) (cqrsAggregate.AggregateModel, error) { +func NewDeviceMetadataFactoryModel(userID, owner, hubID string) func(context.Context, string, string) (cqrsAggregate.AggregateModel, error) { + return func(context.Context, string, string) (cqrsAggregate.AggregateModel, error) { return events.NewDeviceMetadataSnapshotTakenForCommand(userID, owner, hubID), nil } } -func NewServicesMetadataFactoryModel(userID, owner, hubID string) func(ctx context.Context) (cqrsAggregate.AggregateModel, error) { - return func(ctx context.Context) (cqrsAggregate.AggregateModel, error) { +func NewServicesMetadataFactoryModel(userID, owner, hubID string) func(context.Context, string, string) (cqrsAggregate.AggregateModel, error) { + return func(context.Context, string, string) (cqrsAggregate.AggregateModel, error) { return events.NewServiceMetadataSnapshotTakenForCommand(userID, owner, hubID), nil } } -// NewAggregate creates new resource aggreate - it must be created for every run command. -func NewAggregate(resourceID *commands.ResourceId, store eventstore.EventStore, factoryModel cqrsAggregate.FactoryModelFunc, retry cqrsAggregate.RetryFunc) (*Aggregate, error) { +// NewResourceAggregate for creating new resource aggregate. +func NewResourceAggregate(resourceID *commands.ResourceId, store eventstore.EventStore, factoryModel cqrsAggregate.FactoryModelFunc, retry cqrsAggregate.RetryFunc, addLinkedResources bool) (*Aggregate, error) { a := &Aggregate{ eventstore: store, } + addLink := make([]cqrsAggregate.AdditionalModel, 0, 1) + if addLinkedResources { + addLink = append(addLink, cqrsAggregate.AdditionalModel{ + GroupID: resourceID.GetDeviceId(), + AggregateID: commands.NewResourceID(resourceID.GetDeviceId(), commands.ResourceLinksHref).ToUUID().String(), + }) + } + cqrsAg, err := cqrsAggregate.NewAggregate(resourceID.GetDeviceId(), resourceID.ToUUID().String(), retry, store, factoryModel, - func(template string, args ...interface{}) { - // TODO: add debug log - }) + func(string, ...interface{}) { + // no-op - we don't want to log debug/trace messages + }, + // load also links state + addLink..., + ) if err != nil { return nil, fmt.Errorf("cannot create aggregate for resource: %w", err) } @@ -65,6 +82,11 @@ func NewAggregate(resourceID *commands.ResourceId, store eventstore.EventStore, return a, nil } +// NewAggregate creates new resource aggreate - it must be created for every run command. +func NewAggregate(resourceID *commands.ResourceId, store eventstore.EventStore, factoryModel cqrsAggregate.FactoryModelFunc, retry cqrsAggregate.RetryFunc) (*Aggregate, error) { + return NewResourceAggregate(resourceID, store, factoryModel, retry, false) +} + func (a *Aggregate) HandleCommand(ctx context.Context, cmd cqrsAggregate.Command) ([]eventstore.Event, error) { events, err := a.ag.HandleCommand(ctx, cmd) if err == nil { @@ -82,18 +104,20 @@ var ( ) func validatePublish(request *commands.PublishResourceLinksRequest) error { - if len(request.Resources) == 0 { + resources := request.GetResources() + if len(resources) == 0 { return status.Errorf(codes.InvalidArgument, "empty publish is not accepted") } - for _, res := range request.Resources { - if len(res.Href) <= 1 || res.Href[:1] != "/" { + for _, res := range resources { + href := res.GetHref() + if len(href) <= 1 || href[:1] != "/" { return status.Errorf(codes.InvalidArgument, "invalid resource href") } - if res.DeviceId == "" { + if res.GetDeviceId() == "" { return status.Errorf(codes.InvalidArgument, "invalid device id") } } - if request.DeviceId == "" { + if request.GetDeviceId() == "" { return errInvalidDeviceID } return nil @@ -103,7 +127,7 @@ func validateUnpublish(request *commands.UnpublishResourceLinksRequest) error { if request.GetDeviceId() == "" { return errInvalidDeviceID } - for _, href := range request.Hrefs { + for _, href := range request.GetHrefs() { if href == "" { return status.Errorf(codes.InvalidArgument, "invalid resource id") } @@ -112,7 +136,7 @@ func validateUnpublish(request *commands.UnpublishResourceLinksRequest) error { } func validateNotifyContentChanged(request *commands.NotifyResourceChangedRequest) error { - if request.Content == nil { + if request.GetContent() == nil { return errInvalidContent } if request.GetResourceId().GetDeviceId() == "" { @@ -128,7 +152,7 @@ func validateUpdateResourceContent(request *commands.UpdateResourceRequest) erro if err := checkTimeToLive(request.GetTimeToLive()); err != nil { return err } - if request.Content == nil { + if request.GetContent() == nil { return errInvalidContent } if request.GetResourceId().GetDeviceId() == "" { @@ -160,7 +184,7 @@ func validateRetrieveResource(request *commands.RetrieveResourceRequest) error { } func validateConfirmResourceUpdate(request *commands.ConfirmResourceUpdateRequest) error { - if request.Content == nil { + if request.GetContent() == nil { return errInvalidContent } if request.GetResourceId().GetDeviceId() == "" { @@ -177,7 +201,7 @@ func validateConfirmResourceUpdate(request *commands.ConfirmResourceUpdateReques } func validateConfirmResourceRetrieve(request *commands.ConfirmResourceRetrieveRequest) error { - if request.Content == nil { + if request.GetContent() == nil { return errInvalidContent } if request.GetResourceId().GetDeviceId() == "" { @@ -276,9 +300,9 @@ func (a *Aggregate) cleanUpToSnapshot(ctx context.Context, events []eventstore.E err := a.eventstore.RemoveUpToVersion(ctx, []eventstore.VersionQuery{{GroupID: event.GroupID(), AggregateID: event.AggregateID(), Version: event.Version()}}) if err != nil && !errors.Is(err, eventstore.ErrNotSupported) { if ru, ok := event.(interface{ GetResourceId() *commands.ResourceId }); ok { - log.Info("unable to remove events up to snapshot with version('%v') for resource('%v')", event.Version(), ru.GetResourceId()) + log.Infof("unable to remove events up to snapshot with version('%v') for resource('%v')", event.Version(), ru.GetResourceId()) } else { - log.Info("unable to remove events up to snapshot(%v) with version('%v') of deviceId('%v')", event.EventType(), event.Version(), event.GroupID()) + log.Infof("unable to remove events up to snapshot(%v) with version('%v') of deviceId('%v')", event.EventType(), event.Version(), event.GroupID()) } } } diff --git a/resource-aggregate/service/aggregate_test.go b/resource-aggregate/service/aggregate_test.go index 7885f9aaa..91b19faf4 100644 --- a/resource-aggregate/service/aggregate_test.go +++ b/resource-aggregate/service/aggregate_test.go @@ -2,7 +2,7 @@ package service_test import ( "context" - "fmt" + "errors" "testing" "time" @@ -27,7 +27,6 @@ import ( raTest "github.com/plgd-dev/hub/v2/resource-aggregate/test" hubTest "github.com/plgd-dev/hub/v2/test" "github.com/plgd-dev/hub/v2/test/config" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace/noop" "google.golang.org/grpc/codes" @@ -99,12 +98,12 @@ func TestAggregateHandlePublishResourceLinks(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(cfg.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -113,7 +112,7 @@ func TestAggregateHandlePublishResourceLinks(t *testing.T) { naClient.Close() }() - assert.NoError(t, err) + require.NoError(t, err) for _, tt := range test { tfunc := func(t *testing.T) { ag, err := service.NewAggregate(commands.NewResourceID(tt.args.request.GetDeviceId(), commands.ResourceLinksHref), eventstore, service.NewResourceLinksFactoryModel(tt.args.userID, tt.args.owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) @@ -123,7 +122,7 @@ func TestAggregateHandlePublishResourceLinks(t *testing.T) { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) require.True(t, ok) - assert.Equal(t, tt.want, s.Code()) + require.Equal(t, tt.want, s.Code()) } else { require.NoError(t, err) service.PublishEvents(publisher, tt.args.userID, tt.args.request.GetDeviceId(), ag.ResourceID(), events, logger) @@ -137,7 +136,7 @@ func testHandlePublishResource(ctx context.Context, t *testing.T, publisher *pub pc := testMakePublishResourceRequest(deviceID, hrefs) ag, err := service.NewAggregate(commands.NewResourceID(pc.GetDeviceId(), commands.ResourceLinksHref), eventstore, service.NewResourceLinksFactoryModel(userID, owner, hubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) events, err := ag.PublishResourceLinks(ctx, pc) require.NoError(t, err) service.PublishEvents(publisher, userID, deviceID, ag.ResourceID(), events, log.Get()) @@ -150,7 +149,7 @@ func TestAggregateDuplicitPublishResource(t *testing.T) { const owner = "owner" pool, err := ants.NewPool(16) - assert.NoError(t, err) + require.NoError(t, err) defer pool.Release() cfg := raTest.MakeConfig(t) @@ -172,7 +171,7 @@ func TestAggregateDuplicitPublishResource(t *testing.T) { require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() ag, err := service.NewAggregate(commands.NewResourceID(deviceID, commands.ResourceLinksHref), eventstore, service.NewResourceLinksFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) @@ -181,21 +180,21 @@ func TestAggregateDuplicitPublishResource(t *testing.T) { events, err := ag.PublishResourceLinks(ctx, pc1) require.NoError(t, err) - assert.Equal(t, 1, len(events)) + require.Len(t, events, 1) ag2, err := service.NewAggregate(commands.NewResourceID(deviceID, commands.ResourceLinksHref), eventstore, service.NewResourceLinksFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) require.NoError(t, err) pc2 := testMakePublishResourceRequest(deviceID, []string{resourceID}) events, err = ag2.PublishResourceLinks(ctx, pc2) require.NoError(t, err) - assert.Empty(t, events) + require.Empty(t, events) ag3, err := service.NewAggregate(commands.NewResourceID(deviceID, commands.ResourceLinksHref), eventstore, service.NewResourceLinksFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) require.NoError(t, err) pc3 := testMakePublishResourceRequest(deviceID, []string{resourceID, resourceID, resourceID}) events, err = ag3.PublishResourceLinks(ctx, pc3) require.NoError(t, err) - assert.Empty(t, events) + require.Empty(t, events) } func TestAggregateHandleUnpublishResource(t *testing.T) { @@ -224,12 +223,12 @@ func TestAggregateHandleUnpublishResource(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(cfg.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -243,14 +242,14 @@ func TestAggregateHandleUnpublishResource(t *testing.T) { pc := testMakeUnpublishResourceRequest(deviceID, []string{resourceID}) ag, err := service.NewAggregate(commands.NewResourceID(pc.GetDeviceId(), commands.ResourceLinksHref), eventstore, service.NewResourceLinksFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) events, err := ag.UnpublishResourceLinks(ctx, pc) - assert.NoError(t, err) + require.NoError(t, err) service.PublishEvents(publisher, userID, deviceID, ag.ResourceID(), events, logger) _, err = ag.UnpublishResourceLinks(ctx, pc) - assert.NoError(t, err) + require.NoError(t, err) } func TestAggregateHandleUnpublishAllResources(t *testing.T) { @@ -278,12 +277,12 @@ func TestAggregateHandleUnpublishAllResources(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(cfg.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -297,14 +296,14 @@ func TestAggregateHandleUnpublishAllResources(t *testing.T) { pc := testMakeUnpublishResourceRequest(deviceID, []string{}) ag, err := service.NewAggregate(commands.NewResourceID(pc.GetDeviceId(), commands.ResourceLinksHref), eventstore, service.NewResourceLinksFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) events, err := ag.UnpublishResourceLinks(ctx, pc) - assert.NoError(t, err) - assert.Equal(t, 1, len(events)) + require.NoError(t, err) + require.Len(t, events, 1) - unpublishedResourceLinks := (events[0].(*raEvents.ResourceLinksUnpublished)).Hrefs - assert.Equal(t, 3, len(unpublishedResourceLinks)) - assert.Contains(t, unpublishedResourceLinks, resourceID1, resourceID2, resourceID3) + unpublishedResourceLinks := (events[0].(*raEvents.ResourceLinksUnpublished)).GetHrefs() + require.Len(t, unpublishedResourceLinks, 3) + require.Contains(t, unpublishedResourceLinks, resourceID1, resourceID2, resourceID3) service.PublishEvents(publisher, userID, deviceID, ag.ResourceID(), events, logger) @@ -339,12 +338,12 @@ func TestAggregateHandleUnpublishResourceSubset(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(cfg.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -356,20 +355,20 @@ func TestAggregateHandleUnpublishResourceSubset(t *testing.T) { testHandlePublishResource(ctx, t, publisher, eventstore, userID, deviceID, owner, cfg.HubID, []string{resourceID1, resourceID2, resourceID3, resourceID4}) ag, err := service.NewAggregate(commands.NewResourceID(deviceID, commands.ResourceLinksHref), eventstore, service.NewResourceLinksFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) pc := testMakeUnpublishResourceRequest(deviceID, []string{resourceID1, resourceID3}) events, err := ag.UnpublishResourceLinks(ctx, pc) - assert.NoError(t, err) - assert.Equal(t, 1, len(events)) - assert.Equal(t, []string{resourceID1, resourceID3}, (events[0].(*raEvents.ResourceLinksUnpublished)).Hrefs) + require.NoError(t, err) + require.Len(t, events, 1) + require.Equal(t, []string{resourceID1, resourceID3}, (events[0].(*raEvents.ResourceLinksUnpublished)).GetHrefs()) service.PublishEvents(publisher, userID, deviceID, ag.ResourceID(), events, logger) pc = testMakeUnpublishResourceRequest(deviceID, []string{resourceID1, resourceID4, resourceID4}) events, err = ag.UnpublishResourceLinks(ctx, pc) - assert.NoError(t, err) - assert.Equal(t, 1, len(events)) - assert.Equal(t, []string{resourceID4}, (events[0].(*raEvents.ResourceLinksUnpublished)).Hrefs) + require.NoError(t, err) + require.Len(t, events, 1) + require.Equal(t, []string{resourceID4}, (events[0].(*raEvents.ResourceLinksUnpublished)).GetHrefs()) } func testMakePublishResourceRequest(deviceID string, href []string) *commands.PublishResourceLinksRequest { @@ -652,12 +651,12 @@ func TestAggregateHandleNotifyContentChanged(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(cfg.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -669,7 +668,7 @@ func TestAggregateHandleNotifyContentChanged(t *testing.T) { testHandlePublishResource(ctx, t, publisher, eventstore, userID, deviceID, owner, cfg.HubID, []string{resourceID}) ag, err := service.NewAggregate(commands.NewResourceID(deviceID, resourceID), eventstore, service.NewResourceStateFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -678,12 +677,12 @@ func TestAggregateHandleNotifyContentChanged(t *testing.T) { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) require.True(t, ok) - assert.Equal(t, tt.wantStatusCode, s.Code()) + require.Equal(t, tt.wantStatusCode, s.Code()) return } require.NoError(t, err) if tt.wantEvents { - assert.NotEmpty(t, gotEvents) + require.NotEmpty(t, gotEvents) } }) } @@ -770,16 +769,16 @@ func TestAggregateHandleUpdateResourceContent(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() ag, err := service.NewAggregate(commands.NewResourceID(deviceID, resourceID), eventstore, service.NewResourceStateFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -793,12 +792,12 @@ func TestAggregateHandleUpdateResourceContent(t *testing.T) { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) require.True(t, ok) - assert.Equal(t, tt.wantStatusCode, s.Code()) + require.Equal(t, tt.wantStatusCode, s.Code()) return } require.NoError(t, err) if tt.wantEvents { - assert.NotEmpty(t, gotEvents) + require.NotEmpty(t, gotEvents) } time.Sleep(tt.args.sleep) }) @@ -857,12 +856,12 @@ func TestAggregateHandleConfirmResourceUpdate(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() ag, err := service.NewAggregate(commands.NewResourceID(deviceID, resourceID), eventstore, service.NewResourceStateFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) @@ -884,12 +883,12 @@ func TestAggregateHandleConfirmResourceUpdate(t *testing.T) { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) require.True(t, ok) - assert.Equal(t, tt.wantStatusCode, s.Code()) + require.Equal(t, tt.wantStatusCode, s.Code()) return } require.NoError(t, err) if tt.wantEvents { - assert.NotEmpty(t, gotEvents) + require.NotEmpty(t, gotEvents) } }) } @@ -967,16 +966,16 @@ func TestAggregateHandleRetrieveResource(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() ag, err := service.NewAggregate(commands.NewResourceID(deviceID, resourceID), eventstore, service.NewResourceStateFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -989,12 +988,12 @@ func TestAggregateHandleRetrieveResource(t *testing.T) { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) require.True(t, ok) - assert.Equal(t, tt.wantStatusCode, s.Code()) + require.Equal(t, tt.wantStatusCode, s.Code()) return } require.NoError(t, err) if tt.wantEvents { - assert.NotEmpty(t, gotEvents) + require.NotEmpty(t, gotEvents) } time.Sleep(tt.args.sleep) }) @@ -1053,16 +1052,16 @@ func TestAggregateHandleNotifyResourceContentResourceProcessed(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() ag, err := service.NewAggregate(commands.NewResourceID(deviceID, resourceID), eventstore, service.NewResourceStateFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) _, err = ag.NotifyResourceChanged(ctx, testMakeNotifyResourceChangedRequest(deviceID, resourceID, 0)) require.NoError(t, err) @@ -1080,12 +1079,12 @@ func TestAggregateHandleNotifyResourceContentResourceProcessed(t *testing.T) { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) require.True(t, ok) - assert.Equal(t, tt.wantStatusCode, s.Code()) + require.Equal(t, tt.wantStatusCode, s.Code()) return } require.NoError(t, err) if tt.wantEvents { - assert.NotEmpty(t, gotEvents) + require.NotEmpty(t, gotEvents) } }) } @@ -1093,7 +1092,7 @@ func TestAggregateHandleNotifyResourceContentResourceProcessed(t *testing.T) { func testListDevicesOfUserFunc(userID string) ([]string, codes.Code, error) { if userID == testUnauthorizedUser { - return nil, codes.Unauthenticated, fmt.Errorf("unauthorized access") + return nil, codes.Unauthenticated, errors.New("unauthorized access") } return testUserDevices, codes.OK, nil } @@ -1171,16 +1170,16 @@ func TestAggregateHandleDeleteResource(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() ag, err := service.NewAggregate(commands.NewResourceID(deviceID, resourceID), eventstore, service.NewResourceStateFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1193,12 +1192,12 @@ func TestAggregateHandleDeleteResource(t *testing.T) { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) require.True(t, ok) - assert.Equal(t, tt.wantStatusCode, s.Code()) + require.Equal(t, tt.wantStatusCode, s.Code()) return } require.NoError(t, err) if tt.wantEvents { - assert.NotEmpty(t, gotEvents) + require.NotEmpty(t, gotEvents) } time.Sleep(tt.args.sleep) }) @@ -1258,16 +1257,16 @@ func TestAggregateHandleConfirmResourceDelete(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() ag, err := service.NewAggregate(commands.NewResourceID(deviceID, resourceID), eventstore, service.NewResourceStateFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) _, err = ag.NotifyResourceChanged(ctx, testMakeNotifyResourceChangedRequest(deviceID, resourceID, 0)) require.NoError(t, err) @@ -1285,13 +1284,13 @@ func TestAggregateHandleConfirmResourceDelete(t *testing.T) { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) require.True(t, ok) - assert.Equal(t, tt.wantStatusCode, s.Code()) + require.Equal(t, tt.wantStatusCode, s.Code()) return } require.NoError(t, err) if tt.wantEvents { - assert.NotEmpty(t, gotEvents) + require.NotEmpty(t, gotEvents) } }) } @@ -1369,16 +1368,16 @@ func TestAggregateHandleCreateResource(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() ag, err := service.NewAggregate(commands.NewResourceID(deviceID, resourceID), eventstore, service.NewResourceStateFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1391,12 +1390,12 @@ func TestAggregateHandleCreateResource(t *testing.T) { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) require.True(t, ok) - assert.Equal(t, tt.wantStatusCode, s.Code()) + require.Equal(t, tt.wantStatusCode, s.Code()) return } require.NoError(t, err) if tt.wantEvents { - assert.NotEmpty(t, gotEvents) + require.NotEmpty(t, gotEvents) } time.Sleep(tt.args.sleep) }) @@ -1456,16 +1455,16 @@ func TestAggregateHandleConfirmResourceCreate(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() ag, err := service.NewAggregate(commands.NewResourceID(deviceID, resourceID), eventstore, service.NewResourceStateFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) - assert.NoError(t, err) + require.NoError(t, err) _, err = ag.NotifyResourceChanged(ctx, testMakeNotifyResourceChangedRequest(deviceID, resourceID, 0)) require.NoError(t, err) @@ -1483,13 +1482,13 @@ func TestAggregateHandleConfirmResourceCreate(t *testing.T) { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) require.True(t, ok) - assert.Equal(t, tt.wantStatusCode, s.Code()) + require.Equal(t, tt.wantStatusCode, s.Code()) return } require.NoError(t, err) if tt.wantEvents { - assert.NotEmpty(t, gotEvents) + require.NotEmpty(t, gotEvents) } }) } diff --git a/resource-aggregate/service/cancelDeviceMetadataUpdates_test.go b/resource-aggregate/service/cancelDeviceMetadataUpdates_test.go index ec3501ab5..d4cdf4088 100644 --- a/resource-aggregate/service/cancelDeviceMetadataUpdates_test.go +++ b/resource-aggregate/service/cancelDeviceMetadataUpdates_test.go @@ -89,12 +89,12 @@ func TestAggregateHandleCancelPendingMetadataUpdates(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(cfg.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -212,12 +212,12 @@ func TestRequestHandlerCancelPendingMetadataUpdates(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(cfg.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -244,10 +244,10 @@ func TestRequestHandlerCancelPendingMetadataUpdates(t *testing.T) { for _, tt := range test { tfunc := func(t *testing.T) { - ctx := kitNetGrpc.CtxWithIncomingToken(ctx, config.CreateJwtToken(t, jwt.MapClaims{ + cpmuCtx := kitNetGrpc.CtxWithIncomingToken(ctx, config.CreateJwtToken(t, jwt.MapClaims{ "sub": tt.args.userID, })) - want, err := requestHandler.CancelPendingMetadataUpdates(ctx, tt.args.request) + want, err := requestHandler.CancelPendingMetadataUpdates(cpmuCtx, tt.args.request) if tt.wantErr { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) diff --git a/resource-aggregate/service/cancelResourceCommands_test.go b/resource-aggregate/service/cancelResourceCommands_test.go index 614021c52..76bdd1ed0 100644 --- a/resource-aggregate/service/cancelResourceCommands_test.go +++ b/resource-aggregate/service/cancelResourceCommands_test.go @@ -162,12 +162,12 @@ func TestRequestHandlerCancelPendingCommands(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(cfg.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) diff --git a/resource-aggregate/service/confirmDeviceMetadataUpdate.go b/resource-aggregate/service/confirmDeviceMetadataUpdate.go index f8687cd8d..821279b1a 100644 --- a/resource-aggregate/service/confirmDeviceMetadataUpdate.go +++ b/resource-aggregate/service/confirmDeviceMetadataUpdate.go @@ -47,7 +47,7 @@ func (r RequestHandler) ConfirmDeviceMetadataUpdate(ctx context.Context, request return nil, log.LogAndReturnError(kitNetGrpc.ForwardErrorf(codes.Internal, "cannot validate user access: %v", err)) } - resID := commands.NewResourceID(request.DeviceId, commands.StatusHref) + resID := commands.NewResourceID(request.GetDeviceId(), commands.StatusHref) aggregate, err := NewAggregate(resID, r.eventstore, NewDeviceMetadataFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) if err != nil { return nil, log.LogAndReturnError(kitNetGrpc.ForwardErrorf(codes.InvalidArgument, "cannot confirm device('%v') metadata update: %v", request.GetDeviceId(), err)) diff --git a/resource-aggregate/service/confirmDeviceMetadataUpdate_test.go b/resource-aggregate/service/confirmDeviceMetadataUpdate_test.go index 31eb7d9bc..52fa9987b 100644 --- a/resource-aggregate/service/confirmDeviceMetadataUpdate_test.go +++ b/resource-aggregate/service/confirmDeviceMetadataUpdate_test.go @@ -84,12 +84,12 @@ func TestAggregateHandleConfirmDeviceMetadataUpdate(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(cfg.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -187,12 +187,12 @@ func TestRequestHandlerConfirmDeviceMetadataUpdate(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -220,7 +220,7 @@ func TestRequestHandlerConfirmDeviceMetadataUpdate(t *testing.T) { } require.NoError(t, err) if tt.want != nil { - assert.Equal(t, tt.want.AuditContext, response.AuditContext) + assert.Equal(t, tt.want.GetAuditContext(), response.GetAuditContext()) } } t.Run(tt.name, tfunc) diff --git a/resource-aggregate/service/deleteDevices.go b/resource-aggregate/service/deleteDevices.go index 849f728cd..df4c77ffe 100644 --- a/resource-aggregate/service/deleteDevices.go +++ b/resource-aggregate/service/deleteDevices.go @@ -13,7 +13,7 @@ import ( func getUniqueDeviceIdsFromDeleteRequest(request *commands.DeleteDevicesRequest) []string { deviceIDs := make(strings.Set) - for _, deviceID := range request.DeviceIds { + for _, deviceID := range request.GetDeviceIds() { if deviceID != "" { deviceIDs.Add(deviceID) } diff --git a/resource-aggregate/service/deleteDevices_test.go b/resource-aggregate/service/deleteDevices_test.go index efab95c4d..0f24b59dd 100644 --- a/resource-aggregate/service/deleteDevices_test.go +++ b/resource-aggregate/service/deleteDevices_test.go @@ -139,10 +139,10 @@ func TestRequestHandler_DeleteDevices(t *testing.T) { } require.NoError(t, err) if tt.want != nil { - sort.Strings(tt.want.DeviceIds) - sort.Strings(response.DeviceIds) - require.Equal(t, tt.want.DeviceIds, response.DeviceIds) - require.Equal(t, tt.want.AuditContext, response.AuditContext) + sort.Strings(tt.want.GetDeviceIds()) + sort.Strings(response.GetDeviceIds()) + require.Equal(t, tt.want.GetDeviceIds(), response.GetDeviceIds()) + require.Equal(t, tt.want.GetAuditContext(), response.GetAuditContext()) } }) } diff --git a/resource-aggregate/service/grpcApi.go b/resource-aggregate/service/grpcApi.go index 5e8f8798a..fcecaf4ff 100644 --- a/resource-aggregate/service/grpcApi.go +++ b/resource-aggregate/service/grpcApi.go @@ -118,7 +118,7 @@ func (r RequestHandler) PublishResourceLinks(ctx context.Context, request *comma return nil, log.LogAndReturnError(cannotValidateAccessError(err)) } - resID := commands.NewResourceID(request.DeviceId, commands.ResourceLinksHref) + resID := commands.NewResourceID(request.GetDeviceId(), commands.ResourceLinksHref) aggregate, err := NewAggregate(resID, r.eventstore, NewResourceLinksFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) if err != nil { return nil, log.LogAndReturnError(grpc.ForwardErrorf(codes.InvalidArgument, "cannot publish resource links: %v", err)) @@ -139,7 +139,7 @@ func newPublishResourceLinksResponse(events []eventstore.Event, deviceID string, if rlp, ok := event.(*raEvents.ResourceLinksPublished); ok { return &commands.PublishResourceLinksResponse{ AuditContext: auditContext, - PublishedResources: rlp.Resources, + PublishedResources: rlp.GetResources(), DeviceId: deviceID, } } @@ -156,7 +156,7 @@ func (r RequestHandler) UnpublishResourceLinks(ctx context.Context, request *com return nil, log.LogAndReturnError(cannotValidateAccessError(err)) } - resID := commands.NewResourceID(request.DeviceId, commands.ResourceLinksHref) + resID := commands.NewResourceID(request.GetDeviceId(), commands.ResourceLinksHref) aggregate, err := NewAggregate(resID, r.eventstore, NewResourceLinksFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) if err != nil { return nil, log.LogAndReturnError(grpc.ForwardErrorf(codes.InvalidArgument, "cannot unpublish resource links: %v", err)) @@ -193,7 +193,7 @@ func newUnpublishResourceLinksResponse(events []eventstore.Event, deviceID strin if rlu, ok := event.(*raEvents.ResourceLinksUnpublished); ok { return &commands.UnpublishResourceLinksResponse{ AuditContext: auditContext, - UnpublishedHrefs: rlu.Hrefs, + UnpublishedHrefs: rlu.GetHrefs(), DeviceId: deviceID, } } @@ -205,7 +205,7 @@ func newUnpublishResourceLinksResponse(events []eventstore.Event, deviceID strin } func (r RequestHandler) notifyResourceChanged(ctx context.Context, request *commands.NotifyResourceChangedRequest, userID, owner string) error { - aggregate, err := NewAggregate(request.ResourceId, r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) + aggregate, err := NewResourceAggregate(request.GetResourceId(), r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry), len(request.GetResourceTypes()) == 0) if err != nil { return log.LogAndReturnError(grpc.ForwardErrorf(codes.InvalidArgument, "cannot notify about resource content change: %v", err)) } @@ -243,7 +243,7 @@ func (r RequestHandler) UpdateResource(ctx context.Context, request *commands.Up } request.TimeToLive = checkTimeToLiveForDefault(r.config.Clients.Eventstore.DefaultCommandTimeToLive, request.GetTimeToLive()) - aggregate, err := NewAggregate(request.ResourceId, r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) + aggregate, err := NewResourceAggregate(request.GetResourceId(), r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry), true) if err != nil { return nil, log.LogAndReturnError(grpc.ForwardErrorf(codes.InvalidArgument, "cannot update resource content: %v", err)) } @@ -275,7 +275,7 @@ func (r RequestHandler) ConfirmResourceUpdate(ctx context.Context, request *comm if err != nil { return nil, log.LogAndReturnError(cannotValidateAccessError(err)) } - aggregate, err := NewAggregate(request.ResourceId, r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) + aggregate, err := NewResourceAggregate(request.GetResourceId(), r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry), true) if err != nil { return nil, log.LogAndReturnError(grpc.ForwardErrorf(codes.InvalidArgument, "cannot confirm resource content update: %v", err)) } @@ -299,7 +299,7 @@ func (r RequestHandler) RetrieveResource(ctx context.Context, request *commands. } request.TimeToLive = checkTimeToLiveForDefault(r.config.Clients.Eventstore.DefaultCommandTimeToLive, request.GetTimeToLive()) - aggregate, err := NewAggregate(request.ResourceId, r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) + aggregate, err := NewResourceAggregate(request.GetResourceId(), r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry), true) if err != nil { return nil, log.LogAndReturnError(grpc.ForwardErrorf(codes.InvalidArgument, "cannot retrieve resource content: %v", err)) } @@ -331,7 +331,7 @@ func (r RequestHandler) ConfirmResourceRetrieve(ctx context.Context, request *co if err != nil { return nil, log.LogAndReturnError(cannotValidateAccessError(err)) } - aggregate, err := NewAggregate(request.ResourceId, r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) + aggregate, err := NewResourceAggregate(request.GetResourceId(), r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry), true) if err != nil { return nil, log.LogAndReturnError(grpc.ForwardErrorf(codes.InvalidArgument, "ccannot confirm resource content retrieve: %v", err)) } @@ -356,7 +356,7 @@ func (r RequestHandler) DeleteResource(ctx context.Context, request *commands.De } request.TimeToLive = checkTimeToLiveForDefault(r.config.Clients.Eventstore.DefaultCommandTimeToLive, request.GetTimeToLive()) - aggregate, err := NewAggregate(request.ResourceId, r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) + aggregate, err := NewResourceAggregate(request.GetResourceId(), r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry), true) if err != nil { return nil, log.LogAndReturnError(grpc.ForwardErrorf(codes.InvalidArgument, "cannot delete resource: %v", err)) } @@ -389,7 +389,7 @@ func (r RequestHandler) ConfirmResourceDelete(ctx context.Context, request *comm return nil, log.LogAndReturnError(cannotValidateAccessError(err)) } - aggregate, err := NewAggregate(request.ResourceId, r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) + aggregate, err := NewResourceAggregate(request.GetResourceId(), r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry), true) if err != nil { return nil, log.LogAndReturnError(grpc.ForwardErrorf(codes.InvalidArgument, "cannot confirm resource deletion: %v", err)) } @@ -414,7 +414,7 @@ func (r RequestHandler) CreateResource(ctx context.Context, request *commands.Cr } request.TimeToLive = checkTimeToLiveForDefault(r.config.Clients.Eventstore.DefaultCommandTimeToLive, request.GetTimeToLive()) - aggregate, err := NewAggregate(request.ResourceId, r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) + aggregate, err := NewResourceAggregate(request.GetResourceId(), r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry), true) if err != nil { return nil, log.LogAndReturnError(grpc.ForwardErrorf(codes.InvalidArgument, "cannot create resource: %v", err)) } @@ -447,7 +447,7 @@ func (r RequestHandler) ConfirmResourceCreate(ctx context.Context, request *comm return nil, log.LogAndReturnError(cannotValidateAccessError(err)) } - aggregate, err := NewAggregate(request.ResourceId, r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry)) + aggregate, err := NewResourceAggregate(request.GetResourceId(), r.eventstore, NewResourceStateFactoryModel(userID, owner, r.config.HubID), cqrsAggregate.NewDefaultRetryFunc(r.config.Clients.Eventstore.ConcurrencyExceptionMaxRetry), true) if err != nil { return nil, log.LogAndReturnError(grpc.ForwardErrorf(codes.InvalidArgument, "cannot confirm resource creation: %v", err)) } diff --git a/resource-aggregate/service/grpcApi_test.go b/resource-aggregate/service/grpcApi_test.go index bd3441083..50ae3c3c7 100644 --- a/resource-aggregate/service/grpcApi_test.go +++ b/resource-aggregate/service/grpcApi_test.go @@ -113,12 +113,12 @@ func TestRequestHandlerPublishResource(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -136,12 +136,12 @@ func TestRequestHandlerPublishResource(t *testing.T) { tfunc := func(t *testing.T) { response, err := requestHandler.PublishResourceLinks(ctx, tt.args.request) if tt.wantError { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) + require.NoError(t, err) } if tt.want != nil { - assert.Equal(t, tt.want.AuditContext, response.AuditContext) + require.Equal(t, tt.want.GetAuditContext(), response.GetAuditContext()) } } t.Run(tt.name, tfunc) @@ -232,12 +232,12 @@ func TestRequestHandlerUnpublishResource(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(cfg.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -253,7 +253,7 @@ func TestRequestHandlerUnpublishResource(t *testing.T) { pubReq := testMakePublishResourceRequest(deviceID, []string{href}) _, err = requestHandler.PublishResourceLinks(ctx, pubReq) - assert.NoError(t, err) + require.NoError(t, err) for _, tt := range test { tfunc := func(t *testing.T) { @@ -262,9 +262,9 @@ func TestRequestHandlerUnpublishResource(t *testing.T) { })) response, err := requestHandler.UnpublishResourceLinks(ctx, tt.args.request) if tt.wantError { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) + require.NoError(t, err) } assert.Equal(t, tt.want, response) } @@ -321,12 +321,12 @@ func TestRequestHandlerNotifyResourceChanged(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -344,9 +344,9 @@ func TestRequestHandlerNotifyResourceChanged(t *testing.T) { tfunc := func(t *testing.T) { response, err := requestHandler.NotifyResourceChanged(ctx, tt.args.request) if tt.wantError { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) + require.NoError(t, err) } assert.Equal(t, tt.want, response) } @@ -422,12 +422,12 @@ func TestRequestHandlerUpdateResourceContent(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -448,7 +448,7 @@ func TestRequestHandlerUpdateResourceContent(t *testing.T) { } response, err := requestHandler.UpdateResource(ctx, tt.args.request) if tt.wantError { - assert.Error(t, err) + require.Error(t, err) return } require.NoError(t, err) @@ -519,12 +519,12 @@ func TestRequestHandlerConfirmResourceUpdate(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -547,9 +547,9 @@ func TestRequestHandlerConfirmResourceUpdate(t *testing.T) { tfunc := func(t *testing.T) { response, err := requestHandler.ConfirmResourceUpdate(ctx, tt.args.request) if tt.wantError { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) + require.NoError(t, err) } assert.Equal(t, tt.want, response) } @@ -614,12 +614,12 @@ func TestRequestHandlerRetrieveResource(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -640,7 +640,7 @@ func TestRequestHandlerRetrieveResource(t *testing.T) { } response, err := requestHandler.RetrieveResource(ctx, tt.args.request) if tt.wantError { - assert.Error(t, err) + require.Error(t, err) return } require.NoError(t, err) @@ -711,12 +711,12 @@ func TestRequestHandlerConfirmResourceRetrieve(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -742,9 +742,9 @@ func TestRequestHandlerConfirmResourceRetrieve(t *testing.T) { } response, err := requestHandler.ConfirmResourceRetrieve(ctx, tt.args.request) if tt.wantError { - assert.Error(t, err) + require.Error(t, err) } else { - assert.NoError(t, err) + require.NoError(t, err) } assert.Equal(t, tt.want, response) } @@ -809,12 +809,12 @@ func TestRequestHandlerDeleteResource(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -836,7 +836,7 @@ func TestRequestHandlerDeleteResource(t *testing.T) { } response, err := requestHandler.DeleteResource(ctx, tt.args.request) if tt.wantError { - assert.Error(t, err) + require.Error(t, err) return } require.NoError(t, err) @@ -907,12 +907,12 @@ func TestRequestHandlerConfirmResourceDelete(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -938,7 +938,7 @@ func TestRequestHandlerConfirmResourceDelete(t *testing.T) { } response, err := requestHandler.ConfirmResourceDelete(ctx, tt.args.request) if tt.wantError { - assert.Error(t, err) + require.Error(t, err) return } require.NoError(t, err) @@ -1005,12 +1005,12 @@ func TestRequestHandlerCreateResource(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -1032,7 +1032,7 @@ func TestRequestHandlerCreateResource(t *testing.T) { } response, err := requestHandler.CreateResource(ctx, tt.args.request) if tt.wantError { - assert.Error(t, err) + require.Error(t, err) return } require.NoError(t, err) @@ -1103,12 +1103,12 @@ func TestRequestHandlerConfirmResourceCreate(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -1134,7 +1134,7 @@ func TestRequestHandlerConfirmResourceCreate(t *testing.T) { } response, err := requestHandler.ConfirmResourceCreate(ctx, tt.args.request) if tt.wantError { - assert.Error(t, err) + require.Error(t, err) return } require.NoError(t, err) diff --git a/resource-aggregate/service/service.go b/resource-aggregate/service/service.go index 059ae09f1..bd96873e4 100644 --- a/resource-aggregate/service/service.go +++ b/resource-aggregate/service/service.go @@ -164,7 +164,7 @@ func NewService(ctx context.Context, config Config, fileWatcher *fsnotify.Watche serviceHeartbeat := NewServiceHeartbeat(config, eventStore, publisher, logger) grpcServer.AddCloseFunc(serviceHeartbeat.Close) - requestHandler := NewRequestHandler(config, eventStore, publisher, func(getCtx context.Context, owner string, deviceIDs []string) ([]string, error) { + requestHandler := NewRequestHandler(config, eventStore, publisher, func(getCtx context.Context, _ string, deviceIDs []string) ([]string, error) { getAllDevices := len(deviceIDs) == 0 if !getAllDevices { return ownerCache.GetSelectedDevices(getCtx, deviceIDs) diff --git a/resource-aggregate/service/service_grpc.pb.go b/resource-aggregate/service/service_grpc.pb.go index efecb253c..fb6b9f5ef 100644 --- a/resource-aggregate/service/service_grpc.pb.go +++ b/resource-aggregate/service/service_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc v5.26.1 // source: resource-aggregate/pb/service.proto package service diff --git a/resource-aggregate/service/updateDeviceMetadata.go b/resource-aggregate/service/updateDeviceMetadata.go index 9df379bc6..74cdea693 100644 --- a/resource-aggregate/service/updateDeviceMetadata.go +++ b/resource-aggregate/service/updateDeviceMetadata.go @@ -70,7 +70,7 @@ func (r RequestHandler) updateDeviceMetadata(ctx context.Context, request *comma resID := commands.NewResourceID(request.GetDeviceId(), commands.StatusHref) var latestSnapshot *events.DeviceMetadataSnapshotTakenForCommand - deviceMetadataFactoryModel := func(ctx context.Context) (cqrsAggregate.AggregateModel, error) { + deviceMetadataFactoryModel := func(context.Context, string, string) (cqrsAggregate.AggregateModel, error) { latestSnapshot = events.NewDeviceMetadataSnapshotTakenForCommand(userID, owner, r.config.HubID) return latestSnapshot, nil } diff --git a/resource-aggregate/service/updateDeviceMetadata_test.go b/resource-aggregate/service/updateDeviceMetadata_test.go index 5ca336f71..3f8077b0d 100644 --- a/resource-aggregate/service/updateDeviceMetadata_test.go +++ b/resource-aggregate/service/updateDeviceMetadata_test.go @@ -20,7 +20,6 @@ import ( "github.com/plgd-dev/hub/v2/resource-aggregate/service" raTest "github.com/plgd-dev/hub/v2/resource-aggregate/test" "github.com/plgd-dev/hub/v2/test/config" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace/noop" "google.golang.org/grpc/codes" @@ -105,12 +104,12 @@ func TestAggregateHandleUpdateDeviceMetadata(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, cfg.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(cfg.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -119,7 +118,7 @@ func TestAggregateHandleUpdateDeviceMetadata(t *testing.T) { naClient.Close() }() - assert.NoError(t, err) + require.NoError(t, err) for _, tt := range test { tfunc := func(t *testing.T) { ag, err := service.NewAggregate(commands.NewResourceID(tt.args.request.GetDeviceId(), commands.StatusHref), eventstore, service.NewDeviceMetadataFactoryModel(userID, owner, cfg.HubID), cqrsAggregate.NewDefaultRetryFunc(1)) @@ -129,7 +128,7 @@ func TestAggregateHandleUpdateDeviceMetadata(t *testing.T) { require.Error(t, err) s, ok := status.FromError(kitNetGrpc.ForwardFromError(codes.Unknown, err)) require.True(t, ok) - assert.Equal(t, tt.want, s.Code()) + require.Equal(t, tt.want, s.Code()) return } require.NoError(t, err) @@ -235,12 +234,12 @@ func TestRequestHandlerUpdateDeviceMetadata(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -263,12 +262,12 @@ func TestRequestHandlerUpdateDeviceMetadata(t *testing.T) { } require.NoError(t, err) if tt.want != nil { - assert.Equal(t, tt.want.AuditContext, response.AuditContext) + require.Equal(t, tt.want.GetAuditContext(), response.GetAuditContext()) } if tt.want.GetValidUntil() == 0 { - assert.Equal(t, tt.want.ValidUntil, response.GetValidUntil()) + require.Equal(t, tt.want.GetValidUntil(), response.GetValidUntil()) } else { - assert.Less(t, tt.want.ValidUntil, response.GetValidUntil()) + require.Less(t, tt.want.GetValidUntil(), response.GetValidUntil()) } time.Sleep(tt.args.sleep) } diff --git a/resource-aggregate/service/updateServiceHeartbeat.go b/resource-aggregate/service/updateServiceHeartbeat.go index 84ee82dc0..83e0b6a74 100644 --- a/resource-aggregate/service/updateServiceHeartbeat.go +++ b/resource-aggregate/service/updateServiceHeartbeat.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "sync" "time" @@ -197,7 +198,7 @@ func (s *ServiceHeartbeat) updateServiceMetadata(aggregate *Aggregate, r UpdateS func (s *ServiceHeartbeat) processRequest(r UpdateServiceMetadataReqResp) time.Time { resID := commands.NewResourceID(s.config.HubID, commands.ServicesResourceHref) var snapshot *events.ServiceMetadataSnapshotTakenForCommand - newServicesMetadataFactoryModelFunc := func(ctx context.Context) (cqrsAggregate.AggregateModel, error) { + newServicesMetadataFactoryModelFunc := func(context.Context, string, string) (cqrsAggregate.AggregateModel, error) { snapshot = events.NewServiceMetadataSnapshotTakenForCommand(ServiceUserID, ServiceUserID, s.config.HubID) return snapshot, nil } @@ -336,10 +337,10 @@ func (s *ServiceHeartbeat) pop() []UpdateServiceMetadataReqResp { func (s *ServiceHeartbeat) ProcessRequest(r UpdateServiceMetadataReqResp) error { if r.Request == nil { - return fmt.Errorf("invalid request") + return errors.New("invalid request") } if r.ResponseChan == nil { - return fmt.Errorf("invalid response channel") + return errors.New("invalid response channel") } s.push(r) s.wakeUp() @@ -372,7 +373,7 @@ func (s *ServiceHeartbeat) updateDeviceToExpired(ctx context.Context, serviceID, resID := commands.NewResourceID(deviceID, commands.StatusHref) var latestSnapshot *events.DeviceMetadataSnapshotTakenForCommand - deviceMetadataFactoryModel := func(ctx context.Context) (cqrsAggregate.AggregateModel, error) { + deviceMetadataFactoryModel := func(context.Context, string, string) (cqrsAggregate.AggregateModel, error) { latestSnapshot = events.NewDeviceMetadataSnapshotTakenForCommand(userID, "", s.config.HubID) return latestSnapshot, nil } diff --git a/resource-aggregate/service/updateServiceHeartbeat_test.go b/resource-aggregate/service/updateServiceHeartbeat_test.go index d97a03997..88aa7b3f5 100644 --- a/resource-aggregate/service/updateServiceHeartbeat_test.go +++ b/resource-aggregate/service/updateServiceHeartbeat_test.go @@ -37,12 +37,12 @@ func TestNewServiceHeartbeat(t *testing.T) { err = eventstore.Clear(ctx) require.NoError(t, err) err = eventstore.Close(ctx) - assert.NoError(t, err) + require.NoError(t, err) eventstore, err = mongodb.New(ctx, config.Clients.Eventstore.Connection.MongoDB, fileWatcher, logger, noop.NewTracerProvider(), mongodb.WithUnmarshaler(utils.Unmarshal), mongodb.WithMarshaler(utils.Marshal)) require.NoError(t, err) defer func() { errC := eventstore.Close(ctx) - assert.NoError(t, errC) + require.NoError(t, errC) }() naClient, publisher, err := natsTest.NewClientAndPublisher(config.Clients.Eventbus.NATS, fileWatcher, logger, publisher.WithMarshaler(utils.Marshal)) require.NoError(t, err) @@ -87,15 +87,15 @@ func TestNewServiceHeartbeat(t *testing.T) { chosen, value, ok := reflect.Select(cases) if ok { if chosen == 0 { - assert.Fail(t, "context canceled") + require.Fail(t, "context canceled") } if chosen != 0 { data := value.Interface().(service.UpdateServiceMetadataResponseChanData) - assert.NoError(t, data.Err) + require.NoError(t, data.Err) } } if !ok { - assert.Fail(t, "channel closed") + require.Fail(t, "channel closed") break } } diff --git a/resource-directory/pb/getLatestDeviceETags.pb.go b/resource-directory/pb/getLatestDeviceETags.pb.go index 236fbcf6f..dd23301cf 100644 --- a/resource-directory/pb/getLatestDeviceETags.pb.go +++ b/resource-directory/pb/getLatestDeviceETags.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: resource-directory/pb/getLatestDeviceETags.proto package pb diff --git a/resource-directory/pb/service_grpc.pb.go b/resource-directory/pb/service_grpc.pb.go index 206aa04a2..8793ad8c5 100644 --- a/resource-directory/pb/service_grpc.pb.go +++ b/resource-directory/pb/service_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc v5.26.1 // source: resource-directory/pb/service.proto package pb diff --git a/resource-directory/service/deviceDirectory.go b/resource-directory/service/deviceDirectory.go index 31c4764f0..2e44ccffb 100644 --- a/resource-directory/service/deviceDirectory.go +++ b/resource-directory/service/deviceDirectory.go @@ -1,6 +1,7 @@ package service import ( + "errors" "fmt" "github.com/plgd-dev/device/v2/schema/device" @@ -52,7 +53,7 @@ func NewDeviceDirectory(projection *Projection, deviceIds []string) *DeviceDirec func decodeContent(content *commands.Content, v interface{}) error { if content == nil { - return fmt.Errorf("cannot parse empty content") + return errors.New("cannot parse empty content") } var decoder func([]byte, interface{}) error @@ -131,10 +132,10 @@ func filterDevices(deviceIds strings.Set, deviceIDsFilter []string) strings.Set func (dd *DeviceDirectory) sendDevices(deviceIDs strings.Set, req *pb.GetDevicesRequest, srv pb.GrpcGateway_GetDevicesServer, toReloadDevices strings.Set) (err error) { typeFilter := make(strings.Set) - typeFilter.Add(req.TypeFilter...) + typeFilter.Add(req.GetTypeFilter()...) return dd.projection.LoadDevicesMetadata(deviceIDs, toReloadDevices, func(m *deviceMetadataProjection) error { deviceMetadataUpdated := m.GetDeviceMetadataUpdated() - if !hasMatchingStatus(deviceMetadataUpdated.GetConnection().IsOnline(), req.StatusFilter) { + if !hasMatchingStatus(deviceMetadataUpdated.GetConnection().IsOnline(), req.GetStatusFilter()) { return nil } resourceIdFilter := []*commands.ResourceId{commands.NewResourceID(m.GetDeviceID(), device.ResourceURI)} @@ -160,7 +161,7 @@ func (dd *DeviceDirectory) sendDevices(deviceIDs strings.Set, req *pb.GetDevices } func (dd *DeviceDirectory) GetDevices(req *pb.GetDevicesRequest, srv pb.GrpcGateway_GetDevicesServer) (err error) { - deviceIDs := filterDevices(dd.userDeviceIds, req.DeviceIdFilter) + deviceIDs := filterDevices(dd.userDeviceIds, req.GetDeviceIdFilter()) if len(deviceIDs) == 0 { log.Debug("DeviceDirectory.GetDevices.filterDevices returns empty deviceIDs") return nil diff --git a/resource-directory/service/deviceDirectory_test.go b/resource-directory/service/deviceDirectory_test.go index f2c1d009a..b43de0d09 100644 --- a/resource-directory/service/deviceDirectory_test.go +++ b/resource-directory/service/deviceDirectory_test.go @@ -47,7 +47,7 @@ func TestDeviceDirectoryGetDevices(t *testing.T) { }, wantStatusCode: codes.OK, wantResponse: map[string]*pb.Device{ - ddResource2.Resource.DeviceId: testMakeDeviceResouceProtobuf(ddResource2.Resource.DeviceId, deviceResourceTypes, true), + ddResource2.Resource.GetDeviceId(): testMakeDeviceResouceProtobuf(ddResource2.Resource.GetDeviceId(), deviceResourceTypes, true), }, }, @@ -60,7 +60,7 @@ func TestDeviceDirectoryGetDevices(t *testing.T) { }, wantStatusCode: codes.OK, wantResponse: map[string]*pb.Device{ - ddResource1.Resource.DeviceId: testMakeDeviceResouceProtobuf(ddResource1.Resource.DeviceId, deviceResourceTypes, false), + ddResource1.Resource.GetDeviceId(): testMakeDeviceResouceProtobuf(ddResource1.Resource.GetDeviceId(), deviceResourceTypes, false), }, }, { @@ -72,8 +72,8 @@ func TestDeviceDirectoryGetDevices(t *testing.T) { }, wantStatusCode: codes.OK, wantResponse: map[string]*pb.Device{ - ddResource1.Resource.DeviceId: testMakeDeviceResouceProtobuf(ddResource1.Resource.DeviceId, deviceResourceTypes, false), - ddResource2.Resource.DeviceId: testMakeDeviceResouceProtobuf(ddResource2.Resource.DeviceId, deviceResourceTypes, true), + ddResource1.Resource.GetDeviceId(): testMakeDeviceResouceProtobuf(ddResource1.Resource.GetDeviceId(), deviceResourceTypes, false), + ddResource2.Resource.GetDeviceId(): testMakeDeviceResouceProtobuf(ddResource2.Resource.GetDeviceId(), deviceResourceTypes, true), }, }, { @@ -94,20 +94,20 @@ func TestDeviceDirectoryGetDevices(t *testing.T) { }, wantStatusCode: codes.OK, wantResponse: map[string]*pb.Device{ - ddResource1.Resource.DeviceId: testMakeDeviceResouceProtobuf(ddResource1.Resource.DeviceId, deviceResourceTypes, false), - ddResource2.Resource.DeviceId: testMakeDeviceResouceProtobuf(ddResource2.Resource.DeviceId, deviceResourceTypes, true), + ddResource1.Resource.GetDeviceId(): testMakeDeviceResouceProtobuf(ddResource1.Resource.GetDeviceId(), deviceResourceTypes, false), + ddResource2.Resource.GetDeviceId(): testMakeDeviceResouceProtobuf(ddResource2.Resource.GetDeviceId(), deviceResourceTypes, true), }, }, { name: "project_one_device", args: args{ request: &pb.GetDevicesRequest{ - DeviceIdFilter: []string{ddResource1.Resource.DeviceId}, + DeviceIdFilter: []string{ddResource1.Resource.GetDeviceId()}, }, }, wantStatusCode: codes.OK, wantResponse: map[string]*pb.Device{ - ddResource1.Resource.DeviceId: testMakeDeviceResouceProtobuf(ddResource1.Resource.DeviceId, deviceResourceTypes, false), + ddResource1.Resource.GetDeviceId(): testMakeDeviceResouceProtobuf(ddResource1.Resource.GetDeviceId(), deviceResourceTypes, false), }, }, } @@ -269,20 +269,20 @@ func testCreateResourceDeviceEventstores() (resourceEventStore *mockEvents.MockE resourceEventStore = mockEvents.NewMockEventStore() // without cloud state - resourceEventStore.Append(ddResource0.DeviceId, commands.MakeLinksResourceUUID(ddResource0.DeviceId).String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{ddResource0.Resource}, ddResource0.GetDeviceId(), events.MakeEventMeta("a", 0, 0, "hubID"))) - resourceEventStore.Append(ddResource0.DeviceId, ddResource0.Resource.ToUUID().String(), mockEvents.MakeResourceChangedEvent(ddResource0.Resource.GetResourceID(), ddResource0.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"))) + resourceEventStore.Append(ddResource0.GetDeviceId(), commands.MakeLinksResourceUUID(ddResource0.GetDeviceId()).String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{ddResource0.Resource}, ddResource0.GetDeviceId(), events.MakeEventMeta("a", 0, 0, "hubID"))) + resourceEventStore.Append(ddResource0.GetDeviceId(), ddResource0.Resource.ToUUID().String(), mockEvents.MakeResourceChangedEvent(ddResource0.Resource.GetResourceID(), ddResource0.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"), []string{"type0"})) - resourceEventStore.Append(ddResource1.DeviceId, commands.MakeLinksResourceUUID(ddResource1.DeviceId).String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{ddResource1.Resource}, ddResource1.GetDeviceId(), events.MakeEventMeta("a", 0, 0, "hubID"))) - resourceEventStore.Append(ddResource1.DeviceId, ddResource1.Resource.ToUUID().String(), mockEvents.MakeResourceChangedEvent(ddResource1.Resource.GetResourceID(), ddResource1.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"))) - resourceEventStore.Append(ddResource1Cloud.DeviceId, ddResource1Cloud.AggregateID(), mockEvents.MakeDeviceMetadata(ddResource1Cloud.DeviceId, ddResource1Cloud, events.MakeEventMeta("a", 0, 0, "hubID"))) + resourceEventStore.Append(ddResource1.GetDeviceId(), commands.MakeLinksResourceUUID(ddResource1.GetDeviceId()).String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{ddResource1.Resource}, ddResource1.GetDeviceId(), events.MakeEventMeta("a", 0, 0, "hubID"))) + resourceEventStore.Append(ddResource1.GetDeviceId(), ddResource1.Resource.ToUUID().String(), mockEvents.MakeResourceChangedEvent(ddResource1.Resource.GetResourceID(), ddResource1.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"), []string{"type1"})) + resourceEventStore.Append(ddResource1Cloud.GetDeviceId(), ddResource1Cloud.AggregateID(), mockEvents.MakeDeviceMetadata(ddResource1Cloud.GetDeviceId(), ddResource1Cloud, events.MakeEventMeta("a", 0, 0, "hubID"))) // with cloud state - online - resourceEventStore.Append(ddResource2.DeviceId, commands.MakeLinksResourceUUID(ddResource2.DeviceId).String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{ddResource2.Resource}, ddResource2.Resource.GetDeviceId(), events.MakeEventMeta("a", 0, 0, "hubID"))) - resourceEventStore.Append(ddResource2.DeviceId, ddResource2.Resource.ToUUID().String(), mockEvents.MakeResourceChangedEvent(ddResource2.Resource.GetResourceID(), ddResource2.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"))) - resourceEventStore.Append(ddResource2Cloud.DeviceId, ddResource2Cloud.AggregateID(), mockEvents.MakeDeviceMetadata(ddResource2Cloud.DeviceId, ddResource2Cloud, events.MakeEventMeta("a", 0, 0, "hubID"))) + resourceEventStore.Append(ddResource2.GetDeviceId(), commands.MakeLinksResourceUUID(ddResource2.GetDeviceId()).String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{ddResource2.Resource}, ddResource2.Resource.GetDeviceId(), events.MakeEventMeta("a", 0, 0, "hubID"))) + resourceEventStore.Append(ddResource2.GetDeviceId(), ddResource2.Resource.ToUUID().String(), mockEvents.MakeResourceChangedEvent(ddResource2.Resource.GetResourceID(), ddResource2.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"), []string{"type2"})) + resourceEventStore.Append(ddResource2Cloud.GetDeviceId(), ddResource2Cloud.AggregateID(), mockEvents.MakeDeviceMetadata(ddResource2Cloud.GetDeviceId(), ddResource2Cloud, events.MakeEventMeta("a", 0, 0, "hubID"))) // without device resource - resourceEventStore.Append(ddResource4Cloud.DeviceId, ddResource4Cloud.AggregateID(), mockEvents.MakeDeviceMetadata(ddResource4Cloud.DeviceId, ddResource2Cloud, events.MakeEventMeta("a", 0, 1, "hubID"))) + resourceEventStore.Append(ddResource4Cloud.GetDeviceId(), ddResource4Cloud.AggregateID(), mockEvents.MakeDeviceMetadata(ddResource4Cloud.GetDeviceId(), ddResource2Cloud, events.MakeEventMeta("a", 0, 1, "hubID"))) return resourceEventStore } @@ -300,6 +300,6 @@ func (s *testGrpcGateway_GetDevicesServer) Send(d *pb.Device) error { if s.got == nil { s.got = make(map[string]*pb.Device) } - s.got[d.Id] = d + s.got[d.GetId()] = d return nil } diff --git a/resource-directory/service/getDevicesMetadata_test.go b/resource-directory/service/getDevicesMetadata_test.go index 88ffa2fd5..db36dedf6 100644 --- a/resource-directory/service/getDevicesMetadata_test.go +++ b/resource-directory/service/getDevicesMetadata_test.go @@ -125,7 +125,7 @@ func TestRequestHandlerGetDevicesMetadata(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/resource-directory/service/getDevices_test.go b/resource-directory/service/getDevices_test.go index c3ec3b128..a3e81b10e 100644 --- a/resource-directory/service/getDevices_test.go +++ b/resource-directory/service/getDevices_test.go @@ -48,7 +48,7 @@ func TestRequestHandlerGetDevicesParallel(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) virtualdevice.CreateDevices(ctx, t, numDevices, numResources, test.StringToApplicationProtocol(config.ACTIVE_COAP_SCHEME)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -135,7 +135,7 @@ func TestRequestHandlerGetDevices(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -161,11 +161,12 @@ func TestRequestHandlerGetDevices(t *testing.T) { break } require.NoError(t, err) - assert.NotEmpty(t, dev.ProtocolIndependentId) + assert.NotEmpty(t, dev.GetProtocolIndependentId()) assert.NotEmpty(t, dev.GetData().GetContent().GetData()) dev.ProtocolIndependentId = "" dev.Metadata.Connection.Id = "" dev.Metadata.Connection.ConnectedAt = 0 + dev.Metadata.Connection.LocalEndpoints = nil dev.Metadata.Connection.ServiceId = "" dev.Metadata.TwinSynchronization.SyncingAt = 0 dev.Metadata.TwinSynchronization.InSyncAt = 0 diff --git a/resource-directory/service/getEvents.go b/resource-directory/service/getEvents.go index b76f00d72..c942a38f2 100644 --- a/resource-directory/service/getEvents.go +++ b/resource-directory/service/getEvents.go @@ -285,7 +285,7 @@ func (p *resourceEvent) Handle(ctx context.Context, iter eventstore.Iter) error } func getDeviceQueries(deviceIDFilter []string, userDeviceIDs strings.Set) []eventstore.GetEventsQuery { - var queries []eventstore.GetEventsQuery + queries := make([]eventstore.GetEventsQuery, 0, len(deviceIDFilter)) for _, deviceID := range deviceIDFilter { if _, ok := userDeviceIDs[deviceID]; !ok { log.Debugf("permission denied, device with id %v skipped", deviceID) @@ -299,7 +299,7 @@ func getDeviceQueries(deviceIDFilter []string, userDeviceIDs strings.Set) []even } func getResourceQueries(resourceFilter []*pb.ResourceIdFilter, userDeviceIDs strings.Set) []eventstore.GetEventsQuery { - var queries []eventstore.GetEventsQuery + queries := make([]eventstore.GetEventsQuery, 0, len(resourceFilter)) for _, filter := range resourceFilter { if !userDeviceIDs.HasOneOf(filter.GetResourceId().GetDeviceId()) { log.Debugf("permission denied, resource belonging to device %v skipped", filter.GetResourceId().GetDeviceId()) @@ -314,7 +314,7 @@ func getResourceQueries(resourceFilter []*pb.ResourceIdFilter, userDeviceIDs str } func getUserDeviceQueries(userDeviceIds strings.Set) []eventstore.GetEventsQuery { - var queries []eventstore.GetEventsQuery + queries := make([]eventstore.GetEventsQuery, 0, len(userDeviceIds)) for device := range userDeviceIds { queries = append(queries, eventstore.GetEventsQuery{ GroupID: device, @@ -342,13 +342,13 @@ func (r *RequestHandler) GetEvents(req *pb.GetEventsRequest, srv pb.GrpcGateway_ } // for backward compatibility and http api - req.ResourceIdFilter = append(req.ResourceIdFilter, req.ConvertHTTPResourceIDFilter()...) + req.ResourceIdFilter = append(req.GetResourceIdFilter(), req.ConvertHTTPResourceIDFilter()...) var queries []eventstore.GetEventsQuery - if len(req.DeviceIdFilter) == 0 && len(req.GetResourceIdFilter()) == 0 { + if len(req.GetDeviceIdFilter()) == 0 && len(req.GetResourceIdFilter()) == 0 { queries = getUserDeviceQueries(mapUserDeviceIDs) } else { - queries = getDeviceQueries(req.DeviceIdFilter, mapUserDeviceIDs) + queries = getDeviceQueries(req.GetDeviceIdFilter(), mapUserDeviceIDs) queries = append(queries, getResourceQueries(req.GetResourceIdFilter(), mapUserDeviceIDs)...) if len(queries) == 0 { log.Debugf("None of the filters are satisfied for user %v", owner) @@ -356,7 +356,7 @@ func (r *RequestHandler) GetEvents(req *pb.GetEventsRequest, srv pb.GrpcGateway_ } } - err = r.eventStore.GetEvents(srv.Context(), queries, req.TimestampFilter, &resourceEvent{srv: srv}) + err = r.eventStore.GetEvents(srv.Context(), queries, req.GetTimestampFilter(), &resourceEvent{srv: srv}) if err != nil { return log.LogAndReturnError(status.Errorf(status.Convert(err).Code(), "cannot get events: %v", err)) } diff --git a/resource-directory/service/getEventsSnapshot_test.go b/resource-directory/service/getEventsSnapshot_test.go index 5e265f62c..8a5ca80e9 100644 --- a/resource-directory/service/getEventsSnapshot_test.go +++ b/resource-directory/service/getEventsSnapshot_test.go @@ -51,7 +51,7 @@ func TestRequestHandlerGetEventsStateSnapshot(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -106,8 +106,9 @@ func TestRequestHandlerGetEventsStateSnapshot(t *testing.T) { case *events.ResourceStateSnapshotTaken: pbTest.CmpResourceStateSnapshotTaken(t, &events.ResourceStateSnapshotTaken{ ResourceId: commands.NewResourceID(deviceID, lightHref), - LatestResourceChange: pbTest.MakeResourceChanged(t, deviceID, lightHref, "", makeLightData(0)), + LatestResourceChange: pbTest.MakeResourceChanged(t, deviceID, lightHref, test.TestResourceLightInstanceResourceTypes, "", makeLightData(0)), AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, event) default: assert.Fail(t, "unexpected event", "event: %v", ev) diff --git a/resource-directory/service/getEvents_test.go b/resource-directory/service/getEvents_test.go index ec346e0c1..87b84f743 100644 --- a/resource-directory/service/getEvents_test.go +++ b/resource-directory/service/getEvents_test.go @@ -52,8 +52,9 @@ func getAllOnboardEvents(t *testing.T, deviceID string, links []schema.ResourceL Type: &pb.GetEventsResponse_ResourceStateSnapshotTaken{ ResourceStateSnapshotTaken: &events.ResourceStateSnapshotTaken{ ResourceId: rid, - LatestResourceChange: pbTest.MakeResourceChanged(t, deviceID, rid.GetHref(), "", r.Representation), + LatestResourceChange: pbTest.MakeResourceChanged(t, deviceID, rid.GetHref(), r.ResourceTypes, "", r.Representation), AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID), + ResourceTypes: r.ResourceTypes, }, }, }) @@ -83,7 +84,7 @@ func TestRequestHandlerGetEventsOnOnboard(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/resource-directory/service/getHubConfiguration_test.go b/resource-directory/service/getHubConfiguration_test.go index 10ff190cb..b93961302 100644 --- a/resource-directory/service/getHubConfiguration_test.go +++ b/resource-directory/service/getHubConfiguration_test.go @@ -35,7 +35,7 @@ func TestRequestHandlerGetHubConfiguration(t *testing.T) { tearDown := service.SetUp(ctx, t) defer tearDown() - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -52,9 +52,9 @@ func TestRequestHandlerGetHubConfiguration(t *testing.T) { require.Error(t, err) } else { require.NoError(t, err) - require.NotEmpty(t, got.CertificateAuthorities) + require.NotEmpty(t, got.GetCertificateAuthorities()) got.CertificateAuthorities = "" - require.NotEqual(t, int64(0), got.CurrentTime) + require.NotEqual(t, int64(0), got.GetCurrentTime()) got.CurrentTime = 0 test.CheckProtobufs(t, tt.want, got, test.RequireToCheckFunc(require.Equal)) } diff --git a/resource-directory/service/getPendingCommands_test.go b/resource-directory/service/getPendingCommands_test.go index 5193f3573..b99d882fd 100644 --- a/resource-directory/service/getPendingCommands_test.go +++ b/resource-directory/service/getPendingCommands_test.go @@ -69,7 +69,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { "power": 1, }), }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, }, }, @@ -101,7 +102,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { DeviceId: deviceID, Href: platform.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: []string{platform.ResourceType}, }, }, }, @@ -119,7 +121,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { "power": 1, }), }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -130,7 +133,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -148,7 +152,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { "power": 1, }), }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, }, }, @@ -169,7 +174,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { DeviceId: deviceID, Href: platform.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: []string{platform.ResourceType}, }, }, }, @@ -197,7 +203,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { "power": 1, }), }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -218,7 +225,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -246,7 +254,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { "power": 1, }), }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceLightInstanceResourceTypes, }, }, }, @@ -274,7 +283,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { "power": 1, }), }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -285,7 +295,8 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { DeviceId: deviceID, Href: device.ResourceURI, }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, "", service.DeviceUserID), + ResourceTypes: test.TestResourceDeviceResourceTypes, }, }, }, @@ -335,7 +346,7 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -350,9 +361,9 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { secureGWShutdown() createFn := func(timeToLive time.Duration) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + createCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.CreateResource(ctx, &pb.CreateResourceRequest{ + _, errC := c.CreateResource(createCtx, &pb.CreateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -362,27 +373,27 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { }, TimeToLive: int64(timeToLive), }) - require.Error(t, err) + require.Error(t, errC) } createFn(time.Millisecond * 500) // for test expired event createFn(0) retrieveFn := func(timeToLive time.Duration) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + retrieveCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.GetResourceFromDevice(ctx, &pb.GetResourceFromDeviceRequest{ + _, errG := c.GetResourceFromDevice(retrieveCtx, &pb.GetResourceFromDeviceRequest{ ResourceId: commands.NewResourceID(deviceID, platform.ResourceURI), TimeToLive: int64(timeToLive), }) - require.Error(t, err) + require.Error(t, errG) } retrieveFn(time.Millisecond * 500) // for test expired event retrieveFn(0) updateFn := func(timeToLive time.Duration) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateResource(ctx, &pb.UpdateResourceRequest{ + _, errU := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -392,32 +403,32 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) { }, TimeToLive: int64(timeToLive), }) - require.Error(t, err) + require.Error(t, errU) } updateFn(time.Millisecond * 500) // for test expired event updateFn(0) deleteFn := func(timeToLive time.Duration) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + deleteCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.DeleteResource(ctx, &pb.DeleteResourceRequest{ + _, errD := c.DeleteResource(deleteCtx, &pb.DeleteResourceRequest{ ResourceId: commands.NewResourceID(deviceID, device.ResourceURI), TimeToLive: int64(timeToLive), }) - require.Error(t, err) + require.Error(t, errD) } deleteFn(time.Millisecond * 500) // for test expired event deleteFn(0) updateDeviceMetadata := func(timeToLive time.Duration) { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateDeviceMetadata(ctx, &pb.UpdateDeviceMetadataRequest{ + _, errU := c.UpdateDeviceMetadata(updateCtx, &pb.UpdateDeviceMetadataRequest{ DeviceId: deviceID, TwinEnabled: false, TimeToLive: int64(timeToLive), }) - require.Error(t, err) + require.Error(t, errU) } updateDeviceMetadata(time.Millisecond * 500) // for test expired event updateDeviceMetadata(0) // for test expired event diff --git a/resource-directory/service/getResourceLinks_test.go b/resource-directory/service/getResourceLinks_test.go index b6fb18c75..5a622a298 100644 --- a/resource-directory/service/getResourceLinks_test.go +++ b/resource-directory/service/getResourceLinks_test.go @@ -56,7 +56,7 @@ func TestRequestHandlerGetResourceLinks(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/resource-directory/service/getResources_test.go b/resource-directory/service/getResources_test.go index 86b74bb2c..f0ac7a214 100644 --- a/resource-directory/service/getResources_test.go +++ b/resource-directory/service/getResources_test.go @@ -46,7 +46,7 @@ func TestRequestHandlerGetResources(t *testing.T) { want: []*pb.Resource{ { Types: []string{types.CORE_LIGHT}, - Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceLightInstanceHref("1"), "", + Data: pbTest.MakeResourceChanged(t, deviceID, test.TestResourceLightInstanceHref("1"), test.TestResourceLightInstanceResourceTypes, "", map[string]interface{}{ "state": false, "power": uint64(0), @@ -65,7 +65,7 @@ func TestRequestHandlerGetResources(t *testing.T) { defer tearDown() ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/resource-directory/service/grpcApi.go b/resource-directory/service/grpcApi.go index ca473238c..14a9765d4 100644 --- a/resource-directory/service/grpcApi.go +++ b/resource-directory/service/grpcApi.go @@ -195,7 +195,7 @@ func NewRequestHandler( } func NewEventStoreModelFactory() func(context.Context, string, string) (eventstore.Model, error) { - return func(ctx context.Context, deviceID, resourceID string) (eventstore.Model, error) { + return func(_ context.Context, deviceID, resourceID string) (eventstore.Model, error) { switch resourceID { case commands.MakeLinksResourceUUID(deviceID).String(): return NewResourceLinksProjection(deviceID), nil diff --git a/resource-directory/service/projection.go b/resource-directory/service/projection.go index 73e408e9f..cde5507b1 100644 --- a/resource-directory/service/projection.go +++ b/resource-directory/service/projection.go @@ -151,14 +151,14 @@ func (p *Projection) wantToReloadDevice(rl *resourceLinksProjection, hrefFilter if len(hrefFilter) > 0 && !hrefFilter[res.GetHref()] { return true } - if !hasMatchingType(res.ResourceTypes, typeFilter) { + if !hasMatchingType(res.GetResourceTypes(), typeFilter) { return true } reload := true p.Models(func(eventstore.Model) (wantNext bool) { reload = false return true - }, commands.NewResourceID(rl.GetDeviceID(), res.Href)) + }, commands.NewResourceID(rl.GetDeviceID(), res.GetHref())) if reload { finalReload = true return false @@ -173,7 +173,7 @@ func (p *Projection) loadResourceWithLinks(deviceID string, hrefFilter map[strin if len(hrefFilter) > 0 && !hrefFilter[res.GetHref()] { return false } - if !hasMatchingType(res.ResourceTypes, typeFilter) { + if !hasMatchingType(res.GetResourceTypes(), typeFilter) { return false } return true @@ -204,7 +204,7 @@ func (p *Projection) loadResourceWithLinks(deviceID string, hrefFilter map[strin Resource: res, }) return err == nil - }, commands.NewResourceID(rl.GetDeviceID(), res.Href)) + }, commands.NewResourceID(rl.GetDeviceID(), res.GetHref())) return true }) return err diff --git a/resource-directory/service/resourceDirectory.go b/resource-directory/service/resourceDirectory.go index e85466553..045d8fb9d 100644 --- a/resource-directory/service/resourceDirectory.go +++ b/resource-directory/service/resourceDirectory.go @@ -35,14 +35,14 @@ func (rd *ResourceDirectory) sendResourceLinks(srv pb.GrpcGateway_GetResourceLin } func (rd *ResourceDirectory) GetResourceLinks(in *pb.GetResourceLinksRequest, srv pb.GrpcGateway_GetResourceLinksServer) error { - deviceIDs := filterDevices(rd.userDeviceIds, in.DeviceIdFilter) + deviceIDs := filterDevices(rd.userDeviceIds, in.GetDeviceIdFilter()) if len(deviceIDs) == 0 { log.Debug("ResourceDirectory.GetResourceLinks.filterDevices returns empty deviceIDs") return nil } typeFilter := make(strings.Set) - typeFilter.Add(in.TypeFilter...) + typeFilter.Add(in.GetTypeFilter()...) toReloadDevices := make(strings.Set) err := rd.sendResourceLinks(srv, deviceIDs, typeFilter, toReloadDevices) diff --git a/resource-directory/service/resourceDirectory_test.go b/resource-directory/service/resourceDirectory_test.go index 02218cfdd..64e0a116c 100644 --- a/resource-directory/service/resourceDirectory_test.go +++ b/resource-directory/service/resourceDirectory_test.go @@ -20,7 +20,6 @@ import ( "github.com/plgd-dev/hub/v2/test" "github.com/plgd-dev/hub/v2/test/config" pbTest "github.com/plgd-dev/hub/v2/test/pb" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" ) @@ -86,7 +85,7 @@ func TestResourceDirectoryGetResourceLinks(t *testing.T) { var s testGrpcGateway_GetResourceLinksServer err := rd.GetResourceLinks(tt.args.request, &s) require.NoError(t, err) - test.CheckProtobufs(t, tt.want, s.got, test.AssertToCheckFunc(assert.Equal)) + test.CheckProtobufs(t, tt.want, s.got, test.RequireToCheckFunc(require.Equal)) } t.Run(tt.name, fn) } @@ -112,10 +111,10 @@ func testCreateEventstore() *mockEvents.MockEventStore { store.Append(Resource1.DeviceId, commands.MakeLinksResourceUUID(Resource1.DeviceId).String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{Resource1.Resource}, Resource1.GetDeviceId(), events.MakeEventMeta("a", 0, 0, "hubID"))) store.Append(Resource2.DeviceId, commands.MakeLinksResourceUUID(Resource2.DeviceId).String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{Resource2.Resource}, Resource2.GetDeviceId(), events.MakeEventMeta("a", 0, 0, "hubID"))) store.Append(Resource3.DeviceId, commands.MakeLinksResourceUUID(Resource3.DeviceId).String(), mockEvents.MakeResourceLinksPublishedEvent([]*commands.Resource{Resource3.Resource}, Resource3.GetDeviceId(), events.MakeEventMeta("a", 0, 0, "hubID"))) - store.Append(Resource0.DeviceId, Resource0.ToUUID().String(), mockEvents.MakeResourceChangedEvent(Resource0.Resource.GetResourceID(), Resource0.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"))) - store.Append(Resource1.DeviceId, Resource1.ToUUID().String(), mockEvents.MakeResourceChangedEvent(Resource1.Resource.GetResourceID(), Resource1.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"))) - store.Append(Resource2.DeviceId, Resource2.ToUUID().String(), mockEvents.MakeResourceChangedEvent(Resource2.Resource.GetResourceID(), Resource2.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"))) - store.Append(Resource3.DeviceId, Resource3.ToUUID().String(), mockEvents.MakeResourceChangedEvent(Resource3.Resource.GetResourceID(), Resource3.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"))) + store.Append(Resource0.DeviceId, Resource0.ToUUID().String(), mockEvents.MakeResourceChangedEvent(Resource0.Resource.GetResourceID(), Resource0.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"), Resource0.ResourceTypes)) + store.Append(Resource1.DeviceId, Resource1.ToUUID().String(), mockEvents.MakeResourceChangedEvent(Resource1.Resource.GetResourceID(), Resource1.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"), Resource1.ResourceTypes)) + store.Append(Resource2.DeviceId, Resource2.ToUUID().String(), mockEvents.MakeResourceChangedEvent(Resource2.Resource.GetResourceID(), Resource2.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"), Resource2.ResourceTypes)) + store.Append(Resource3.DeviceId, Resource3.ToUUID().String(), mockEvents.MakeResourceChangedEvent(Resource3.Resource.GetResourceID(), Resource3.Content, events.MakeEventMeta("a", 0, 0, "hubID"), mockEvents.MakeAuditContext("userId", "0"), Resource3.ResourceTypes)) return store } @@ -132,6 +131,6 @@ func (s *testGrpcGateway_GetResourceLinksServer) Send(d *events.ResourceLinksPub if s.got == nil { s.got = make(map[string]*events.ResourceLinksPublished) } - s.got[d.DeviceId] = pbTest.CleanUpResourceLinksPublished(d, true) + s.got[d.GetDeviceId()] = pbTest.CleanUpResourceLinksPublished(d, true) return nil } diff --git a/resource-directory/service/resourceLinksProjection.go b/resource-directory/service/resourceLinksProjection.go index dd3a76515..de825dd6d 100644 --- a/resource-directory/service/resourceLinksProjection.go +++ b/resource-directory/service/resourceLinksProjection.go @@ -117,7 +117,7 @@ func (rlp *resourceLinksProjection) ToResourceLinksPublished(typeFilter strings. rlp.private.lock.RLock() defer rlp.private.lock.RUnlock() for _, resource := range rlp.private.snapshot.GetResources() { - if hasMatchingType(resource.ResourceTypes, typeFilter) { + if hasMatchingType(resource.GetResourceTypes(), typeFilter) { resources = append(resources, resource) } } diff --git a/resource-directory/service/resourceProjection.go b/resource-directory/service/resourceProjection.go index 6cf0bb8e2..e4ea61d9a 100644 --- a/resource-directory/service/resourceProjection.go +++ b/resource-directory/service/resourceProjection.go @@ -54,8 +54,8 @@ func (rp *resourceProjection) handleResourceStateSnapshotTakenLocked(eu eventsto if err := eu.Unmarshal(&s); err != nil { return err } - rp.private.resourceID = s.ResourceId - rp.private.content = s.LatestResourceChange + rp.private.resourceID = s.GetResourceId() + rp.private.content = s.GetLatestResourceChange() rp.private.onResourceChangedVersion = eu.Version() rp.private.resourceUpdatePendings = s.GetResourceUpdatePendings() rp.private.resourceCreatePendings = s.GetResourceCreatePendings() @@ -69,7 +69,7 @@ func (rp *resourceProjection) handleResourceChangedLocked(eu eventstore.EventUnm if err := eu.Unmarshal(&s); err != nil { return err } - rp.private.resourceID = s.ResourceId + rp.private.resourceID = s.GetResourceId() rp.private.content = &s rp.private.onResourceChangedVersion = eu.Version() return nil @@ -81,7 +81,7 @@ func (rp *resourceProjection) handleResourceUpdatePendingLocked(eu eventstore.Ev return err } rp.private.resourceUpdatePendings = append(rp.private.resourceUpdatePendings, &s) - rp.private.resourceID = s.ResourceId + rp.private.resourceID = s.GetResourceId() return nil } @@ -90,7 +90,7 @@ func (rp *resourceProjection) handleResourceUpdatedLocked(eu eventstore.EventUnm if err := eu.Unmarshal(&s); err != nil { return err } - rp.private.resourceID = s.ResourceId + rp.private.resourceID = s.GetResourceId() tmp := make([]*events.ResourceUpdatePending, 0, 16) var found bool for _, cu := range rp.private.resourceUpdatePendings { @@ -111,7 +111,7 @@ func (rp *resourceProjection) handleResourceRetrievePendingLocked(eu eventstore. if err := eu.Unmarshal(&s); err != nil { return err } - rp.private.resourceID = s.ResourceId + rp.private.resourceID = s.GetResourceId() rp.private.resourceRetrievePendings = append(rp.private.resourceRetrievePendings, &s) return nil } @@ -121,7 +121,7 @@ func (rp *resourceProjection) handleResourceDeletePendingLocked(eu eventstore.Ev if err := eu.Unmarshal(&s); err != nil { return err } - rp.private.resourceID = s.ResourceId + rp.private.resourceID = s.GetResourceId() rp.private.resourceDeletePendings = append(rp.private.resourceDeletePendings, &s) return nil } @@ -131,7 +131,7 @@ func (rp *resourceProjection) handleResourceRetrievedLocked(eu eventstore.EventU if err := eu.Unmarshal(&s); err != nil { return err } - rp.private.resourceID = s.ResourceId + rp.private.resourceID = s.GetResourceId() tmp := make([]*events.ResourceRetrievePending, 0, 16) var found bool for _, cu := range rp.private.resourceRetrievePendings { @@ -152,7 +152,7 @@ func (rp *resourceProjection) handleResourceDeletedLocked(eu eventstore.EventUnm if err := eu.Unmarshal(&s); err != nil { return err } - rp.private.resourceID = s.ResourceId + rp.private.resourceID = s.GetResourceId() tmp := make([]*events.ResourceDeletePending, 0, 16) var found bool for _, cu := range rp.private.resourceDeletePendings { @@ -174,7 +174,7 @@ func (rp *resourceProjection) handleResourceCreatePendingLocked(eu eventstore.Ev return err } rp.private.resourceCreatePendings = append(rp.private.resourceCreatePendings, &s) - rp.private.resourceID = s.ResourceId + rp.private.resourceID = s.GetResourceId() return nil } @@ -183,7 +183,7 @@ func (rp *resourceProjection) handleResourceCreatedLocked(eu eventstore.EventUnm if err := eu.Unmarshal(&s); err != nil { return err } - rp.private.resourceID = s.ResourceId + rp.private.resourceID = s.GetResourceId() tmp := make([]*events.ResourceCreatePending, 0, 16) var found bool for _, cu := range rp.private.resourceCreatePendings { diff --git a/resource-directory/service/resourceShadow.go b/resource-directory/service/resourceShadow.go index 99d4b1910..93b880c68 100644 --- a/resource-directory/service/resourceShadow.go +++ b/resource-directory/service/resourceShadow.go @@ -84,12 +84,13 @@ func updateContentForResponseForETag(v *pb.ResourceIdFilter, val *pb.Resource) b continue } rc := val.GetData() - val.Data = &events.ResourceChanged{} - val.Data.CopyData(rc) - val.Data.Status = commands.Status_NOT_MODIFIED - val.Data.Content = &commands.Content{ + data := &events.ResourceChanged{} + data.CopyData(rc) + data.Status = commands.Status_NOT_MODIFIED + data.Content = &commands.Content{ CoapContentFormat: int32(-1), } + val.Data = data return true } return false @@ -236,7 +237,7 @@ func (rd *ResourceTwin) sendDevicesMetadata(srv pb.GrpcGateway_GetDevicesMetadat } return nil } - if len(typeFilter) > 0 && !typeFilter.HasOneOf(res.ResourceTypes...) { + if len(typeFilter) > 0 && !typeFilter.HasOneOf(res.GetResourceTypes()...) { return nil } return rd.projection.LoadDevicesMetadata(strings.MakeSet(m.GetDeviceID()), toReloadDevices, func(m *deviceMetadataProjection) error { @@ -254,9 +255,9 @@ func (rd *ResourceTwin) sendDevicesMetadata(srv pb.GrpcGateway_GetDevicesMetadat } func (rd *ResourceTwin) GetDevicesMetadata(req *pb.GetDevicesMetadataRequest, srv pb.GrpcGateway_GetDevicesMetadataServer) error { - deviceIDs := filterDevices(rd.userDeviceIds, req.DeviceIdFilter) + deviceIDs := filterDevices(rd.userDeviceIds, req.GetDeviceIdFilter()) typeFilter := make(strings.Set) - typeFilter.Add(req.TypeFilter...) + typeFilter.Add(req.GetTypeFilter()...) toReloadDevices := make(strings.Set) err := rd.sendDevicesMetadata(srv, deviceIDs, typeFilter, toReloadDevices) if err != nil { diff --git a/resource-directory/service/resourceShadow_test.go b/resource-directory/service/resourceShadow_test.go index df326fe8e..087278913 100644 --- a/resource-directory/service/resourceShadow_test.go +++ b/resource-directory/service/resourceShadow_test.go @@ -19,7 +19,6 @@ import ( "github.com/plgd-dev/hub/v2/resource-directory/service" "github.com/plgd-dev/hub/v2/test" "github.com/plgd-dev/hub/v2/test/config" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" ) @@ -63,7 +62,8 @@ func TestResourceTwinGetResources(t *testing.T) { DeviceId: Resource1.DeviceId, Href: Resource1.Href, }, - Content: Resource1.Content, + Content: Resource1.Content, + ResourceTypes: Resource1.ResourceTypes, }, Types: Resource1.ResourceTypes, }, @@ -73,7 +73,8 @@ func TestResourceTwinGetResources(t *testing.T) { DeviceId: Resource2.DeviceId, Href: Resource2.Href, }, - Content: Resource2.Content, + Content: Resource2.Content, + ResourceTypes: Resource2.ResourceTypes, }, Types: Resource2.ResourceTypes, }, @@ -94,7 +95,8 @@ func TestResourceTwinGetResources(t *testing.T) { DeviceId: Resource1.DeviceId, Href: Resource1.Href, }, - Content: Resource1.Content, + Content: Resource1.Content, + ResourceTypes: Resource1.ResourceTypes, }, Types: Resource1.ResourceTypes, }, @@ -104,7 +106,8 @@ func TestResourceTwinGetResources(t *testing.T) { DeviceId: Resource3.DeviceId, Href: Resource3.Href, }, - Content: Resource3.Content, + Content: Resource3.Content, + ResourceTypes: Resource3.ResourceTypes, }, Types: Resource3.ResourceTypes, }, @@ -125,7 +128,8 @@ func TestResourceTwinGetResources(t *testing.T) { DeviceId: Resource1.DeviceId, Href: Resource1.Href, }, - Content: Resource1.Content, + Content: Resource1.Content, + ResourceTypes: Resource1.ResourceTypes, }, Types: Resource1.ResourceTypes, }, @@ -135,7 +139,8 @@ func TestResourceTwinGetResources(t *testing.T) { DeviceId: Resource2.DeviceId, Href: Resource2.Href, }, - Content: Resource2.Content, + Content: Resource2.Content, + ResourceTypes: Resource2.ResourceTypes, }, Types: Resource2.ResourceTypes, }, @@ -157,7 +162,8 @@ func TestResourceTwinGetResources(t *testing.T) { DeviceId: Resource1.DeviceId, Href: Resource1.Href, }, - Content: Resource1.Content, + Content: Resource1.Content, + ResourceTypes: Resource1.ResourceTypes, }, Types: Resource1.ResourceTypes, }, @@ -176,7 +182,8 @@ func TestResourceTwinGetResources(t *testing.T) { DeviceId: Resource1.DeviceId, Href: Resource1.Href, }, - Content: Resource1.Content, + Content: Resource1.Content, + ResourceTypes: Resource1.ResourceTypes, }, Types: Resource1.ResourceTypes, }, @@ -186,7 +193,8 @@ func TestResourceTwinGetResources(t *testing.T) { DeviceId: Resource2.DeviceId, Href: Resource2.Href, }, - Content: Resource2.Content, + Content: Resource2.Content, + ResourceTypes: Resource2.ResourceTypes, }, Types: Resource2.ResourceTypes, }, @@ -196,7 +204,8 @@ func TestResourceTwinGetResources(t *testing.T) { DeviceId: Resource3.DeviceId, Href: Resource3.Href, }, - Content: Resource3.Content, + Content: Resource3.Content, + ResourceTypes: Resource3.ResourceTypes, }, Types: Resource3.ResourceTypes, }, @@ -235,8 +244,8 @@ func TestResourceTwinGetResources(t *testing.T) { fmt.Println(tt.name) var s testGrpcGateway_GetResourcesServer err := rd.GetResources(tt.args.req, &s) - assert.NoError(t, err) - test.CheckProtobufs(t, tt.want, s.got, test.AssertToCheckFunc(assert.Equal)) + require.NoError(t, err) + test.CheckProtobufs(t, tt.want, s.got, test.RequireToCheckFunc(require.Equal)) }) } } diff --git a/snapshot-service/pb/README.md b/snapshot-service/pb/README.md index fc2486318..93920f126 100644 --- a/snapshot-service/pb/README.md +++ b/snapshot-service/pb/README.md @@ -4,27 +4,25 @@ ## Table of Contents - [snapshot-service/pb/service.proto](#snapshot-service_pb_service-proto) - - [AppliedConfiguration](#snapshotservice-pb-AppliedConfiguration) - - [AppliedConfiguration.RelationTo](#snapshotservice-pb-AppliedConfiguration-RelationTo) - - [AppliedConfiguration.Resource](#snapshotservice-pb-AppliedConfiguration-Resource) + - [AppliedDeviceConfiguration](#snapshotservice-pb-AppliedDeviceConfiguration) + - [AppliedDeviceConfiguration.RelationTo](#snapshotservice-pb-AppliedDeviceConfiguration-RelationTo) + - [AppliedDeviceConfiguration.Resource](#snapshotservice-pb-AppliedDeviceConfiguration-Resource) - [Condition](#snapshotservice-pb-Condition) - - [Condition.InvokeConfiguration](#snapshotservice-pb-Condition-InvokeConfiguration) - [Configuration](#snapshotservice-pb-Configuration) - [Configuration.Resource](#snapshotservice-pb-Configuration-Resource) - - [DeleteAppliedConfigurationsRequest](#snapshotservice-pb-DeleteAppliedConfigurationsRequest) - - [DeleteAppliedConfigurationsResponse](#snapshotservice-pb-DeleteAppliedConfigurationsResponse) + - [DeleteAppliedDeviceConfigurationsRequest](#snapshotservice-pb-DeleteAppliedDeviceConfigurationsRequest) + - [DeleteAppliedDeviceConfigurationsResponse](#snapshotservice-pb-DeleteAppliedDeviceConfigurationsResponse) - [DeleteConditionsRequest](#snapshotservice-pb-DeleteConditionsRequest) - [DeleteConditionsResponse](#snapshotservice-pb-DeleteConditionsResponse) - [DeleteConfigurationsRequest](#snapshotservice-pb-DeleteConfigurationsRequest) - [DeleteConfigurationsResponse](#snapshotservice-pb-DeleteConfigurationsResponse) - - [GetAppliedConfigurationsRequest](#snapshotservice-pb-GetAppliedConfigurationsRequest) + - [GetAppliedDeviceConfigurationsRequest](#snapshotservice-pb-GetAppliedDeviceConfigurationsRequest) - [GetConditionsRequest](#snapshotservice-pb-GetConditionsRequest) - [GetConfigurationsRequest](#snapshotservice-pb-GetConfigurationsRequest) - - [IdFilter](#snapshotservice-pb-IdFilter) + - [IDFilter](#snapshotservice-pb-IDFilter) - [InvokeConfigurationRequest](#snapshotservice-pb-InvokeConfigurationRequest) - - [ResourceTypes](#snapshotservice-pb-ResourceTypes) - - [AppliedConfiguration.Resource.Status](#snapshotservice-pb-AppliedConfiguration-Resource-Status) + - [AppliedDeviceConfiguration.Resource.Status](#snapshotservice-pb-AppliedDeviceConfiguration-Resource-Status) - [SnapshotService](#snapshotservice-pb-SnapshotService) @@ -39,30 +37,31 @@ - - -### AppliedConfiguration + +### AppliedDeviceConfiguration +TODO naming | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | id | [string](#string) | | | | device_id | [string](#string) | | | -| configuration_id | [AppliedConfiguration.RelationTo](#snapshotservice-pb-AppliedConfiguration-RelationTo) | | | -| on_demaned | [bool](#bool) | | | -| condition_id | [AppliedConfiguration.RelationTo](#snapshotservice-pb-AppliedConfiguration-RelationTo) | | | -| resources | [AppliedConfiguration.Resource](#snapshotservice-pb-AppliedConfiguration-Resource) | repeated | | - +| configuration_id | [AppliedDeviceConfiguration.RelationTo](#snapshotservice-pb-AppliedDeviceConfiguration-RelationTo) | | | +| on_demand | [bool](#bool) | | | +| condition_id | [AppliedDeviceConfiguration.RelationTo](#snapshotservice-pb-AppliedDeviceConfiguration-RelationTo) | | TODO Naming | +| resources | [AppliedDeviceConfiguration.Resource](#snapshotservice-pb-AppliedDeviceConfiguration-Resource) | repeated | TODO naming | +| owner | [string](#string) | | | - -### AppliedConfiguration.RelationTo + +### AppliedDeviceConfiguration.RelationTo +TODO naming | Field | Type | Label | Description | @@ -75,19 +74,17 @@ - + -### AppliedConfiguration.Resource +### AppliedDeviceConfiguration.Resource | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| resource_id | [resourceaggregate.pb.ResourceId](#resourceaggregate-pb-ResourceId) | | | -| configuration_resources_idx | [uint32](#uint32) | | index of resource in configuration resources array. For resource types it could be mutliple resources. | -| status | [AppliedConfiguration.Resource.Status](#snapshotservice-pb-AppliedConfiguration-Resource-Status) | | | -| timestamp_start | [int64](#int64) | | when the rule association was applied | -| valid_until | [int64](#int64) | | how long the command is valid | +| resource_id | [resourceaggregate.pb.ResourceId](#resourceaggregate-pb-ResourceId) | | TODO Jozo href only? | +| correlation_id | [string](#string) | | Reused from invoke command or generated. Can be used to retrieve corresponding pending command. | +| status | [AppliedDeviceConfiguration.Resource.Status](#snapshotservice-pb-AppliedDeviceConfiguration-Resource-Status) | | | | resource_updated | [resourceaggregate.pb.ResourceUpdated](#resourceaggregate-pb-ResourceUpdated) | | | @@ -98,7 +95,7 @@ ### Condition - +driven by resource change event | Field | Type | Label | Description | @@ -107,28 +104,13 @@ | version | [uint64](#uint64) | | | | name | [string](#string) | | | | enabled | [bool](#bool) | | | +| configuration_id | [string](#string) | | | | device_id_filter | [string](#string) | repeated | | | resource_type_filter | [string](#string) | repeated | | | resource_href_filter | [string](#string) | repeated | | -| yq_expression | [string](#string) | | | -| invoke_configuration | [Condition.InvokeConfiguration](#snapshotservice-pb-Condition-InvokeConfiguration) | | | - - - - - - - - -### Condition.InvokeConfiguration - - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| id | [string](#string) | | latest version of cfg | -| keep_updating_on_failure | [bool](#bool) | | | +| jq_expression_filter | [string](#string) | | | | api_access_token | [string](#string) | | token used to update resources in the configuration | +| owner | [string](#string) | | | @@ -147,6 +129,7 @@ | version | [uint64](#uint64) | | | | name | [string](#string) | | | | resources | [Configuration.Resource](#snapshotservice-pb-Configuration-Resource) | repeated | | +| owner | [string](#string) | | | @@ -162,18 +145,17 @@ | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | href | [string](#string) | | | -| resource_types | [ResourceTypes](#snapshotservice-pb-ResourceTypes) | | | | content | [resourceaggregate.pb.Content](#resourceaggregate-pb-Content) | | | -| time_to_live | [int64](#int64) | | optional update command time to live | +| time_to_live | [int64](#int64) | | optional update command time to live, 0 is infinite | - + -### DeleteAppliedConfigurationsRequest +### DeleteAppliedDeviceConfigurationsRequest @@ -186,9 +168,9 @@ - + -### DeleteAppliedConfigurationsResponse +### DeleteAppliedDeviceConfigurationsResponse @@ -209,7 +191,7 @@ | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| id_filter | [IdFilter](#snapshotservice-pb-IdFilter) | repeated | | +| id_filter | [IDFilter](#snapshotservice-pb-IDFilter) | repeated | | @@ -239,7 +221,7 @@ | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| id_filter | [IdFilter](#snapshotservice-pb-IdFilter) | repeated | | +| id_filter | [IDFilter](#snapshotservice-pb-IDFilter) | repeated | | @@ -261,18 +243,18 @@ - - -### GetAppliedConfigurationsRequest + +### GetAppliedDeviceConfigurationsRequest +TODO Naming | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | id_filter | [string](#string) | repeated | | -| configuration_id_filter | [IdFilter](#snapshotservice-pb-IdFilter) | repeated | | +| configuration_id_filter | [IDFilter](#snapshotservice-pb-IDFilter) | repeated | | | device_id_filter | [string](#string) | repeated | | -| condition_id_filter | [string](#string) | repeated | | +| condition_id_filter | [IDFilter](#snapshotservice-pb-IDFilter) | repeated | | @@ -287,7 +269,7 @@ | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| id_filter | [IdFilter](#snapshotservice-pb-IdFilter) | repeated | | +| id_filter | [IDFilter](#snapshotservice-pb-IDFilter) | repeated | | @@ -302,17 +284,17 @@ | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| id_filter | [IdFilter](#snapshotservice-pb-IdFilter) | repeated | | +| id_filter | [IDFilter](#snapshotservice-pb-IDFilter) | repeated | | - - -### IdFilter + +### IDFilter +configuration/123?version=latest :) Jozko spravi :) | Field | Type | Label | Description | @@ -320,7 +302,7 @@ | id | [string](#string) | | | | value | [uint64](#uint64) | | | | all | [bool](#bool) | | | -| max | [bool](#bool) | | | +| latest | [bool](#bool) | | | @@ -335,26 +317,10 @@ | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| id | [string](#string) | | | -| device_id_filter | [string](#string) | repeated | at least one must be set | +| configuration_id | [string](#string) | | applies latest configuration | +| device_id | [string](#string) | | | | force | [bool](#bool) | | force update even if the configuration has already been applied to device | -| keep_updating_on_failure | [bool](#bool) | | if any update resource fails continue with next resource | - - - - - - - - -### ResourceTypes - - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| types | [string](#string) | repeated | all types must match resource | -| min | [uint32](#uint32) | | minimal number of resources that will be updated | +| correlation_id | [string](#string) | | propagated down to the resource update command | @@ -363,19 +329,17 @@ - + -### AppliedConfiguration.Resource.Status +### AppliedDeviceConfiguration.Resource.Status | Name | Number | Description | | ---- | ------ | ----------- | | QUEUED | 0 | | -| INPROGRESS | 1 | | -| WAITING_FOR_REOURCE | 2 | | -| DONE | 3 | | -| TIMEOUT | 4 | | -| FAIL | 5 | | +| PENDING | 1 | | +| DONE | 2 | If done look to resource_updated even update resource failed for resource aggregate. | +| TIMEOUT | 3 | | @@ -398,9 +362,9 @@ | GetConfigurations | [GetConfigurationsRequest](#snapshotservice-pb-GetConfigurationsRequest) | [Configuration](#snapshotservice-pb-Configuration) stream | | | DeleteConfigurations | [DeleteConfigurationsRequest](#snapshotservice-pb-DeleteConfigurationsRequest) | [DeleteConfigurationsResponse](#snapshotservice-pb-DeleteConfigurationsResponse) | | | UpdateConfiguration | [Configuration](#snapshotservice-pb-Configuration) | [Configuration](#snapshotservice-pb-Configuration) | | -| InvokeConfiguration | [InvokeConfigurationRequest](#snapshotservice-pb-InvokeConfigurationRequest) | [AppliedConfiguration](#snapshotservice-pb-AppliedConfiguration) stream | streaming process of update configuration to invoker | -| GetAppliedConfigurations | [GetAppliedConfigurationsRequest](#snapshotservice-pb-GetAppliedConfigurationsRequest) | [AppliedConfiguration](#snapshotservice-pb-AppliedConfiguration) stream | | -| DeleteAppliedConfigurations | [DeleteAppliedConfigurationsRequest](#snapshotservice-pb-DeleteAppliedConfigurationsRequest) | [DeleteAppliedConfigurationsResponse](#snapshotservice-pb-DeleteAppliedConfigurationsResponse) | | +| InvokeConfiguration | [InvokeConfigurationRequest](#snapshotservice-pb-InvokeConfigurationRequest) | [AppliedDeviceConfiguration](#snapshotservice-pb-AppliedDeviceConfiguration) stream | streaming process of update configuration to invoker | +| GetAppliedConfigurations | [GetAppliedDeviceConfigurationsRequest](#snapshotservice-pb-GetAppliedDeviceConfigurationsRequest) | [AppliedDeviceConfiguration](#snapshotservice-pb-AppliedDeviceConfiguration) stream | | +| DeleteAppliedConfigurations | [DeleteAppliedDeviceConfigurationsRequest](#snapshotservice-pb-DeleteAppliedDeviceConfigurationsRequest) | [DeleteAppliedDeviceConfigurationsResponse](#snapshotservice-pb-DeleteAppliedDeviceConfigurationsResponse) | | diff --git a/snapshot-service/pb/doc.html b/snapshot-service/pb/doc.html index ad049f38a..d9d66cfb1 100644 --- a/snapshot-service/pb/doc.html +++ b/snapshot-service/pb/doc.html @@ -179,25 +179,21 @@

Table of Contents

  • - MAppliedConfiguration + MAppliedDeviceConfiguration
  • - MAppliedConfiguration.RelationTo + MAppliedDeviceConfiguration.RelationTo
  • - MAppliedConfiguration.Resource + MAppliedDeviceConfiguration.Resource
  • MCondition
  • -
  • - MCondition.InvokeConfiguration -
  • -
  • MConfiguration
  • @@ -207,11 +203,11 @@

    Table of Contents

  • - MDeleteAppliedConfigurationsRequest + MDeleteAppliedDeviceConfigurationsRequest
  • - MDeleteAppliedConfigurationsResponse + MDeleteAppliedDeviceConfigurationsResponse
  • @@ -231,7 +227,7 @@

    Table of Contents

  • - MGetAppliedConfigurationsRequest + MGetAppliedDeviceConfigurationsRequest
  • @@ -243,20 +239,16 @@

    Table of Contents

  • - MIdFilter + MIDFilter
  • MInvokeConfigurationRequest
  • -
  • - MResourceTypes -
  • -
  • - EAppliedConfiguration.Resource.Status + EAppliedDeviceConfiguration.Resource.Status
  • @@ -280,8 +272,8 @@

    snapshot-service/pb/service.proto

    -

    AppliedConfiguration

    -

    +

    AppliedDeviceConfiguration

    +

    TODO naming

    @@ -306,13 +298,13 @@

    AppliedConfiguration

    - + - + @@ -320,15 +312,22 @@

    AppliedConfiguration

    - + - + - + + + + + + + + @@ -339,8 +338,8 @@

    AppliedConfiguration

    -

    AppliedConfiguration.RelationTo

    -

    +

    AppliedDeviceConfiguration.RelationTo

    +

    TODO naming

    configuration_idAppliedConfiguration.RelationToAppliedDeviceConfiguration.RelationTo

    on_demanedon_demand bool

    condition_idAppliedConfiguration.RelationToAppliedDeviceConfiguration.RelationTo

    TODO Naming

    resourcesAppliedConfiguration.ResourceAppliedDeviceConfiguration.Resource repeated

    TODO naming

    ownerstring

    @@ -370,7 +369,7 @@

    AppliedConfiguration -

    AppliedConfiguration.Resource

    +

    AppliedDeviceConfiguration.Resource

    @@ -384,37 +383,23 @@

    AppliedConfiguration.R

    - + - - + + - + - + - - - - - - - - - - - - - - @@ -430,7 +415,7 @@

    AppliedConfiguration.R

    Condition

    -

    +

    driven by resource change event

    resource_id resourceaggregate.pb.ResourceId

    TODO Jozo href only?

    configuration_resources_idxuint32correlation_idstring

    index of resource in configuration resources array. For resource types it could be mutliple resources.

    Reused from invoke command or generated. Can be used to retrieve corresponding pending command.

    statusAppliedConfiguration.Resource.StatusAppliedDeviceConfiguration.Resource.Status

    timestamp_startint64

    when the rule association was applied

    valid_untilint64

    how long the command is valid

    resource_updated resourceaggregate.pb.ResourceUpdated
    @@ -468,76 +453,52 @@

    Condition

    - + - + - + - + - + - + - - + + - -
    device_id_filterconfiguration_id stringrepeated

    resource_type_filterdevice_id_filter string repeated

    resource_href_filterresource_type_filter string repeated

    yq_expressionresource_href_filter stringrepeated

    invoke_configurationCondition.InvokeConfigurationjq_expression_filterstring

    - - - - - -

    Condition.InvokeConfiguration

    -

    - - - - - - - - - + - - - - - - - - + - + - + @@ -585,6 +546,13 @@

    Configuration

    + + + + + + +
    FieldTypeLabelDescription
    idapi_access_token string

    latest version of cfg

    keep_updating_on_failurebool

    token used to update resources in the configuration

    api_access_tokenowner string

    token used to update resources in the configuration

    ownerstring

    @@ -609,13 +577,6 @@

    Configuration.Resource

    - - resource_types - ResourceTypes - -

    - - content resourceaggregate.pb.Content @@ -627,7 +588,7 @@

    Configuration.Resource

    time_to_live int64 -

    optional update command time to live

    +

    optional update command time to live, 0 is infinite

    @@ -637,7 +598,7 @@

    Configuration.Resource

    -

    DeleteAppliedConfigurationsRequest

    +

    DeleteAppliedDeviceConfigurationsRequest

    @@ -661,7 +622,7 @@

    DeleteAppliedConf -

    DeleteAppliedConfigurationsResponse

    +

    DeleteAppliedDeviceConfigurationsResponse

    @@ -697,7 +658,7 @@

    DeleteConditionsRequest

    id_filter - IdFilter + IDFilter repeated

    @@ -745,7 +706,7 @@

    DeleteConfigurationsRequ id_filter - IdFilter + IDFilter repeated

    @@ -781,8 +742,8 @@

    DeleteConfigurationsRes -

    GetAppliedConfigurationsRequest

    -

    +

    GetAppliedDeviceConfigurationsRequest

    +

    TODO Naming

    @@ -800,7 +761,7 @@

    GetAppliedConfigurat

    - + @@ -814,7 +775,7 @@

    GetAppliedConfigurat

    - + @@ -838,7 +799,7 @@

    GetConditionsRequest

    - + @@ -862,7 +823,7 @@

    GetConfigurationsRequest

    - + @@ -874,8 +835,8 @@

    GetConfigurationsRequestIdFilter

    -

    +

    IDFilter

    +

    configuration/123?version=latest :) Jozko spravi :)

    configuration_id_filterIdFilterIDFilter repeated

    condition_id_filterstringIDFilter repeated

    id_filterIdFilterIDFilter repeated

    id_filterIdFilterIDFilter repeated

    @@ -906,7 +867,7 @@

    IdFilter

    - + @@ -930,17 +891,17 @@

    InvokeConfigurationReques

    - + - + - + - - + + @@ -951,41 +912,10 @@

    InvokeConfigurationReques

    - - - - - - - -
    maxlatest bool

    idconfiguration_id string

    applies latest configuration

    device_id_filterdevice_id stringrepeated

    at least one must be set

    keep_updating_on_failurebool

    if any update resource fails continue with next resource

    - - - - - -

    ResourceTypes

    -

    - - - - - - - - - - + - - - - - - - - + @@ -997,7 +927,7 @@

    ResourceTypes

    -

    AppliedConfiguration.Resource.Status

    +

    AppliedDeviceConfiguration.Resource.Status

    FieldTypeLabelDescription
    typescorrelation_id stringrepeated

    all types must match resource

    minuint32

    minimal number of resources that will be updated

    propagated down to the resource update command

    @@ -1012,32 +942,20 @@

    AppliedConfigur

    - + - - - - - - - - + + - - - - - - - + @@ -1115,21 +1033,21 @@

    SnapshotService

    - + - - + + - - + + @@ -1236,7 +1154,7 @@

    Methods with HTTP bindings

    - + diff --git a/snapshot-service/pb/service.pb.go b/snapshot-service/pb/service.pb.go index 4ed0d1a8f..46b44cf4c 100644 --- a/snapshot-service/pb/service.pb.go +++ b/snapshot-service/pb/service.pb.go @@ -1,7 +1,15 @@ +// TODO overit ze pending command sa nezmaze na neexistujucom resource ak sa device pripoji a nepublishne hned resource +// Overit correlation id - ak sa pouziva rovnake napriec viacerymi resourcami + +// scenare +// - Uzivatel vie vytvorit config, automaticka (backend) inkrementacia verzie +// - Uzivatel updatne config, verzia sa inkrementuje, Modal -> chces aplikovat na vsetky uz provisionnute devici? Informovat uzivatela, ze niektore devici mozu byt offline a command moze vyexpirovat. +// - Uzivatel updatne config, verzia sa inkrementuje, informujeme uzivatela ze vsetky pending commandy z predoslej verzie budu cancelnute ako aj dalsie sekvencne updaty resourcov pre predoslu verziu + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.1 +// protoc v5.26.1 // source: snapshot-service/pb/service.proto package pb @@ -24,65 +32,60 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type AppliedConfiguration_Resource_Status int32 +type AppliedDeviceConfiguration_Resource_Status int32 const ( - AppliedConfiguration_Resource_QUEUED AppliedConfiguration_Resource_Status = 0 - AppliedConfiguration_Resource_INPROGRESS AppliedConfiguration_Resource_Status = 1 - AppliedConfiguration_Resource_WAITING_FOR_REOURCE AppliedConfiguration_Resource_Status = 2 - AppliedConfiguration_Resource_DONE AppliedConfiguration_Resource_Status = 3 - AppliedConfiguration_Resource_TIMEOUT AppliedConfiguration_Resource_Status = 4 - AppliedConfiguration_Resource_FAIL AppliedConfiguration_Resource_Status = 5 + AppliedDeviceConfiguration_Resource_QUEUED AppliedDeviceConfiguration_Resource_Status = 0 + AppliedDeviceConfiguration_Resource_PENDING AppliedDeviceConfiguration_Resource_Status = 1 + AppliedDeviceConfiguration_Resource_DONE AppliedDeviceConfiguration_Resource_Status = 2 // If done look to resource_updated even update resource failed for resource aggregate. + AppliedDeviceConfiguration_Resource_TIMEOUT AppliedDeviceConfiguration_Resource_Status = 3 ) -// Enum value maps for AppliedConfiguration_Resource_Status. +// Enum value maps for AppliedDeviceConfiguration_Resource_Status. var ( - AppliedConfiguration_Resource_Status_name = map[int32]string{ + AppliedDeviceConfiguration_Resource_Status_name = map[int32]string{ 0: "QUEUED", - 1: "INPROGRESS", - 2: "WAITING_FOR_REOURCE", - 3: "DONE", - 4: "TIMEOUT", - 5: "FAIL", - } - AppliedConfiguration_Resource_Status_value = map[string]int32{ - "QUEUED": 0, - "INPROGRESS": 1, - "WAITING_FOR_REOURCE": 2, - "DONE": 3, - "TIMEOUT": 4, - "FAIL": 5, + 1: "PENDING", + 2: "DONE", + 3: "TIMEOUT", + } + AppliedDeviceConfiguration_Resource_Status_value = map[string]int32{ + "QUEUED": 0, + "PENDING": 1, + "DONE": 2, + "TIMEOUT": 3, } ) -func (x AppliedConfiguration_Resource_Status) Enum() *AppliedConfiguration_Resource_Status { - p := new(AppliedConfiguration_Resource_Status) +func (x AppliedDeviceConfiguration_Resource_Status) Enum() *AppliedDeviceConfiguration_Resource_Status { + p := new(AppliedDeviceConfiguration_Resource_Status) *p = x return p } -func (x AppliedConfiguration_Resource_Status) String() string { +func (x AppliedDeviceConfiguration_Resource_Status) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (AppliedConfiguration_Resource_Status) Descriptor() protoreflect.EnumDescriptor { +func (AppliedDeviceConfiguration_Resource_Status) Descriptor() protoreflect.EnumDescriptor { return file_snapshot_service_pb_service_proto_enumTypes[0].Descriptor() } -func (AppliedConfiguration_Resource_Status) Type() protoreflect.EnumType { +func (AppliedDeviceConfiguration_Resource_Status) Type() protoreflect.EnumType { return &file_snapshot_service_pb_service_proto_enumTypes[0] } -func (x AppliedConfiguration_Resource_Status) Number() protoreflect.EnumNumber { +func (x AppliedDeviceConfiguration_Resource_Status) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use AppliedConfiguration_Resource_Status.Descriptor instead. -func (AppliedConfiguration_Resource_Status) EnumDescriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{10, 0, 0} +// Deprecated: Use AppliedDeviceConfiguration_Resource_Status.Descriptor instead. +func (AppliedDeviceConfiguration_Resource_Status) EnumDescriptor() ([]byte, []int) { + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{9, 0, 0} } -type IdFilter struct { +// /configuration/123?version=latest :) Jozko spravi :) +type IDFilter struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -90,14 +93,14 @@ type IdFilter struct { Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // Types that are assignable to Version: // - // *IdFilter_Value - // *IdFilter_All - // *IdFilter_Max - Version isIdFilter_Version `protobuf_oneof:"version"` + // *IDFilter_Value + // *IDFilter_All + // *IDFilter_Latest + Version isIDFilter_Version `protobuf_oneof:"version"` } -func (x *IdFilter) Reset() { - *x = IdFilter{} +func (x *IDFilter) Reset() { + *x = IDFilter{} if protoimpl.UnsafeEnabled { mi := &file_snapshot_service_pb_service_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -105,13 +108,13 @@ func (x *IdFilter) Reset() { } } -func (x *IdFilter) String() string { +func (x *IDFilter) String() string { return protoimpl.X.MessageStringOf(x) } -func (*IdFilter) ProtoMessage() {} +func (*IDFilter) ProtoMessage() {} -func (x *IdFilter) ProtoReflect() protoreflect.Message { +func (x *IDFilter) ProtoReflect() protoreflect.Message { mi := &file_snapshot_service_pb_service_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -123,82 +126,84 @@ func (x *IdFilter) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use IdFilter.ProtoReflect.Descriptor instead. -func (*IdFilter) Descriptor() ([]byte, []int) { +// Deprecated: Use IDFilter.ProtoReflect.Descriptor instead. +func (*IDFilter) Descriptor() ([]byte, []int) { return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{0} } -func (x *IdFilter) GetId() string { +func (x *IDFilter) GetId() string { if x != nil { return x.Id } return "" } -func (m *IdFilter) GetVersion() isIdFilter_Version { +func (m *IDFilter) GetVersion() isIDFilter_Version { if m != nil { return m.Version } return nil } -func (x *IdFilter) GetValue() uint64 { - if x, ok := x.GetVersion().(*IdFilter_Value); ok { +func (x *IDFilter) GetValue() uint64 { + if x, ok := x.GetVersion().(*IDFilter_Value); ok { return x.Value } return 0 } -func (x *IdFilter) GetAll() bool { - if x, ok := x.GetVersion().(*IdFilter_All); ok { +func (x *IDFilter) GetAll() bool { + if x, ok := x.GetVersion().(*IDFilter_All); ok { return x.All } return false } -func (x *IdFilter) GetMax() bool { - if x, ok := x.GetVersion().(*IdFilter_Max); ok { - return x.Max +func (x *IDFilter) GetLatest() bool { + if x, ok := x.GetVersion().(*IDFilter_Latest); ok { + return x.Latest } return false } -type isIdFilter_Version interface { - isIdFilter_Version() +type isIDFilter_Version interface { + isIDFilter_Version() } -type IdFilter_Value struct { +type IDFilter_Value struct { Value uint64 `protobuf:"varint,2,opt,name=value,proto3,oneof"` } -type IdFilter_All struct { +type IDFilter_All struct { All bool `protobuf:"varint,3,opt,name=all,proto3,oneof"` } -type IdFilter_Max struct { - Max bool `protobuf:"varint,4,opt,name=max,proto3,oneof"` +type IDFilter_Latest struct { + Latest bool `protobuf:"varint,4,opt,name=latest,proto3,oneof"` } -func (*IdFilter_Value) isIdFilter_Version() {} +func (*IDFilter_Value) isIDFilter_Version() {} -func (*IdFilter_All) isIdFilter_Version() {} +func (*IDFilter_All) isIDFilter_Version() {} -func (*IdFilter_Max) isIdFilter_Version() {} +func (*IDFilter_Latest) isIDFilter_Version() {} type Condition struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Version uint64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - Enabled bool `protobuf:"varint,4,opt,name=enabled,proto3" json:"enabled,omitempty"` - DeviceIdFilter []string `protobuf:"bytes,5,rep,name=device_id_filter,json=deviceIdFilter,proto3" json:"device_id_filter,omitempty"` - ResourceTypeFilter []string `protobuf:"bytes,6,rep,name=resource_type_filter,json=resourceTypeFilter,proto3" json:"resource_type_filter,omitempty"` - ResourceHrefFilter []string `protobuf:"bytes,7,rep,name=resource_href_filter,json=resourceHrefFilter,proto3" json:"resource_href_filter,omitempty"` - YqExpression string `protobuf:"bytes,8,opt,name=yq_expression,json=yqExpression,proto3" json:"yq_expression,omitempty"` - InvokeConfiguration *Condition_InvokeConfiguration `protobuf:"bytes,9,opt,name=invoke_configuration,json=invokeConfiguration,proto3" json:"invoke_configuration,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Version uint64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Enabled bool `protobuf:"varint,4,opt,name=enabled,proto3" json:"enabled,omitempty"` + ConfigurationId string `protobuf:"bytes,5,opt,name=configuration_id,json=configurationId,proto3" json:"configuration_id,omitempty"` + DeviceIdFilter []string `protobuf:"bytes,6,rep,name=device_id_filter,json=deviceIdFilter,proto3" json:"device_id_filter,omitempty"` + ResourceTypeFilter []string `protobuf:"bytes,7,rep,name=resource_type_filter,json=resourceTypeFilter,proto3" json:"resource_type_filter,omitempty"` + ResourceHrefFilter []string `protobuf:"bytes,8,rep,name=resource_href_filter,json=resourceHrefFilter,proto3" json:"resource_href_filter,omitempty"` + JqExpressionFilter string `protobuf:"bytes,9,opt,name=jq_expression_filter,json=jqExpressionFilter,proto3" json:"jq_expression_filter,omitempty"` + ApiAccessToken string `protobuf:"bytes,10,opt,name=api_access_token,json=apiAccessToken,proto3" json:"api_access_token,omitempty"` // token used to update resources in the configuration + Owner string `protobuf:"bytes,11,opt,name=owner,proto3" json:"owner,omitempty"` } func (x *Condition) Reset() { @@ -261,6 +266,13 @@ func (x *Condition) GetEnabled() bool { return false } +func (x *Condition) GetConfigurationId() string { + if x != nil { + return x.ConfigurationId + } + return "" +} + func (x *Condition) GetDeviceIdFilter() []string { if x != nil { return x.DeviceIdFilter @@ -282,18 +294,25 @@ func (x *Condition) GetResourceHrefFilter() []string { return nil } -func (x *Condition) GetYqExpression() string { +func (x *Condition) GetJqExpressionFilter() string { if x != nil { - return x.YqExpression + return x.JqExpressionFilter } return "" } -func (x *Condition) GetInvokeConfiguration() *Condition_InvokeConfiguration { +func (x *Condition) GetApiAccessToken() string { if x != nil { - return x.InvokeConfiguration + return x.ApiAccessToken } - return nil + return "" +} + +func (x *Condition) GetOwner() string { + if x != nil { + return x.Owner + } + return "" } type GetConditionsRequest struct { @@ -301,7 +320,7 @@ type GetConditionsRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - IdFilter []*IdFilter `protobuf:"bytes,1,rep,name=id_filter,json=idFilter,proto3" json:"id_filter,omitempty"` + IdFilter []*IDFilter `protobuf:"bytes,1,rep,name=id_filter,json=idFilter,proto3" json:"id_filter,omitempty"` } func (x *GetConditionsRequest) Reset() { @@ -336,7 +355,7 @@ func (*GetConditionsRequest) Descriptor() ([]byte, []int) { return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{2} } -func (x *GetConditionsRequest) GetIdFilter() []*IdFilter { +func (x *GetConditionsRequest) GetIdFilter() []*IDFilter { if x != nil { return x.IdFilter } @@ -348,7 +367,7 @@ type DeleteConditionsRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - IdFilter []*IdFilter `protobuf:"bytes,1,rep,name=id_filter,json=idFilter,proto3" json:"id_filter,omitempty"` + IdFilter []*IDFilter `protobuf:"bytes,1,rep,name=id_filter,json=idFilter,proto3" json:"id_filter,omitempty"` } func (x *DeleteConditionsRequest) Reset() { @@ -383,7 +402,7 @@ func (*DeleteConditionsRequest) Descriptor() ([]byte, []int) { return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{3} } -func (x *DeleteConditionsRequest) GetIdFilter() []*IdFilter { +func (x *DeleteConditionsRequest) GetIdFilter() []*IDFilter { if x != nil { return x.IdFilter } @@ -437,61 +456,6 @@ func (x *DeleteConditionsResponse) GetCount() int64 { return 0 } -type ResourceTypes struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Types []string `protobuf:"bytes,1,rep,name=types,proto3" json:"types,omitempty"` // all types must match resource - Min uint32 `protobuf:"varint,2,opt,name=min,proto3" json:"min,omitempty"` // minimal number of resources that will be updated -} - -func (x *ResourceTypes) Reset() { - *x = ResourceTypes{} - if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ResourceTypes) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ResourceTypes) ProtoMessage() {} - -func (x *ResourceTypes) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ResourceTypes.ProtoReflect.Descriptor instead. -func (*ResourceTypes) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{5} -} - -func (x *ResourceTypes) GetTypes() []string { - if x != nil { - return x.Types - } - return nil -} - -func (x *ResourceTypes) GetMin() uint32 { - if x != nil { - return x.Min - } - return 0 -} - type Configuration struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -501,12 +465,13 @@ type Configuration struct { Version uint64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` Resources []*Configuration_Resource `protobuf:"bytes,4,rep,name=resources,proto3" json:"resources,omitempty"` + Owner string `protobuf:"bytes,5,opt,name=owner,proto3" json:"owner,omitempty"` } func (x *Configuration) Reset() { *x = Configuration{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[6] + mi := &file_snapshot_service_pb_service_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -519,7 +484,7 @@ func (x *Configuration) String() string { func (*Configuration) ProtoMessage() {} func (x *Configuration) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[6] + mi := &file_snapshot_service_pb_service_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -532,7 +497,7 @@ func (x *Configuration) ProtoReflect() protoreflect.Message { // Deprecated: Use Configuration.ProtoReflect.Descriptor instead. func (*Configuration) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{6} + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{5} } func (x *Configuration) GetId() string { @@ -563,18 +528,25 @@ func (x *Configuration) GetResources() []*Configuration_Resource { return nil } +func (x *Configuration) GetOwner() string { + if x != nil { + return x.Owner + } + return "" +} + type GetConfigurationsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - IdFilter []*IdFilter `protobuf:"bytes,1,rep,name=id_filter,json=idFilter,proto3" json:"id_filter,omitempty"` + IdFilter []*IDFilter `protobuf:"bytes,1,rep,name=id_filter,json=idFilter,proto3" json:"id_filter,omitempty"` } func (x *GetConfigurationsRequest) Reset() { *x = GetConfigurationsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[7] + mi := &file_snapshot_service_pb_service_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -587,7 +559,7 @@ func (x *GetConfigurationsRequest) String() string { func (*GetConfigurationsRequest) ProtoMessage() {} func (x *GetConfigurationsRequest) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[7] + mi := &file_snapshot_service_pb_service_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -600,10 +572,10 @@ func (x *GetConfigurationsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetConfigurationsRequest.ProtoReflect.Descriptor instead. func (*GetConfigurationsRequest) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{7} + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{6} } -func (x *GetConfigurationsRequest) GetIdFilter() []*IdFilter { +func (x *GetConfigurationsRequest) GetIdFilter() []*IDFilter { if x != nil { return x.IdFilter } @@ -615,13 +587,13 @@ type DeleteConfigurationsRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - IdFilter []*IdFilter `protobuf:"bytes,1,rep,name=id_filter,json=idFilter,proto3" json:"id_filter,omitempty"` + IdFilter []*IDFilter `protobuf:"bytes,1,rep,name=id_filter,json=idFilter,proto3" json:"id_filter,omitempty"` } func (x *DeleteConfigurationsRequest) Reset() { *x = DeleteConfigurationsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[8] + mi := &file_snapshot_service_pb_service_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -634,7 +606,7 @@ func (x *DeleteConfigurationsRequest) String() string { func (*DeleteConfigurationsRequest) ProtoMessage() {} func (x *DeleteConfigurationsRequest) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[8] + mi := &file_snapshot_service_pb_service_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -647,10 +619,10 @@ func (x *DeleteConfigurationsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteConfigurationsRequest.ProtoReflect.Descriptor instead. func (*DeleteConfigurationsRequest) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{8} + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{7} } -func (x *DeleteConfigurationsRequest) GetIdFilter() []*IdFilter { +func (x *DeleteConfigurationsRequest) GetIdFilter() []*IDFilter { if x != nil { return x.IdFilter } @@ -668,7 +640,7 @@ type DeleteConfigurationsResponse struct { func (x *DeleteConfigurationsResponse) Reset() { *x = DeleteConfigurationsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[9] + mi := &file_snapshot_service_pb_service_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -681,7 +653,7 @@ func (x *DeleteConfigurationsResponse) String() string { func (*DeleteConfigurationsResponse) ProtoMessage() {} func (x *DeleteConfigurationsResponse) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[9] + mi := &file_snapshot_service_pb_service_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -694,7 +666,7 @@ func (x *DeleteConfigurationsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteConfigurationsResponse.ProtoReflect.Descriptor instead. func (*DeleteConfigurationsResponse) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{9} + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{8} } func (x *DeleteConfigurationsResponse) GetCount() int64 { @@ -704,39 +676,40 @@ func (x *DeleteConfigurationsResponse) GetCount() int64 { return 0 } -type AppliedConfiguration struct { +type AppliedDeviceConfiguration struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - DeviceId string `protobuf:"bytes,2,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` - ConfigurationId *AppliedConfiguration_RelationTo `protobuf:"bytes,3,opt,name=configuration_id,json=configurationId,proto3" json:"configuration_id,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + DeviceId string `protobuf:"bytes,2,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` + ConfigurationId *AppliedDeviceConfiguration_RelationTo `protobuf:"bytes,3,opt,name=configuration_id,json=configurationId,proto3" json:"configuration_id,omitempty"` // Types that are assignable to ExecutedBy: // - // *AppliedConfiguration_OnDemaned - // *AppliedConfiguration_ConditionId - ExecutedBy isAppliedConfiguration_ExecutedBy `protobuf_oneof:"executed_by"` - Resources []*AppliedConfiguration_Resource `protobuf:"bytes,6,rep,name=resources,proto3" json:"resources,omitempty"` + // *AppliedDeviceConfiguration_OnDemand + // *AppliedDeviceConfiguration_ConditionId + ExecutedBy isAppliedDeviceConfiguration_ExecutedBy `protobuf_oneof:"executed_by"` + Resources []*AppliedDeviceConfiguration_Resource `protobuf:"bytes,6,rep,name=resources,proto3" json:"resources,omitempty"` //TODO naming + Owner string `protobuf:"bytes,7,opt,name=owner,proto3" json:"owner,omitempty"` } -func (x *AppliedConfiguration) Reset() { - *x = AppliedConfiguration{} +func (x *AppliedDeviceConfiguration) Reset() { + *x = AppliedDeviceConfiguration{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[10] + mi := &file_snapshot_service_pb_service_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *AppliedConfiguration) String() string { +func (x *AppliedDeviceConfiguration) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AppliedConfiguration) ProtoMessage() {} +func (*AppliedDeviceConfiguration) ProtoMessage() {} -func (x *AppliedConfiguration) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[10] +func (x *AppliedDeviceConfiguration) ProtoReflect() protoreflect.Message { + mi := &file_snapshot_service_pb_service_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -747,91 +720,98 @@ func (x *AppliedConfiguration) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use AppliedConfiguration.ProtoReflect.Descriptor instead. -func (*AppliedConfiguration) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{10} +// Deprecated: Use AppliedDeviceConfiguration.ProtoReflect.Descriptor instead. +func (*AppliedDeviceConfiguration) Descriptor() ([]byte, []int) { + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{9} } -func (x *AppliedConfiguration) GetId() string { +func (x *AppliedDeviceConfiguration) GetId() string { if x != nil { return x.Id } return "" } -func (x *AppliedConfiguration) GetDeviceId() string { +func (x *AppliedDeviceConfiguration) GetDeviceId() string { if x != nil { return x.DeviceId } return "" } -func (x *AppliedConfiguration) GetConfigurationId() *AppliedConfiguration_RelationTo { +func (x *AppliedDeviceConfiguration) GetConfigurationId() *AppliedDeviceConfiguration_RelationTo { if x != nil { return x.ConfigurationId } return nil } -func (m *AppliedConfiguration) GetExecutedBy() isAppliedConfiguration_ExecutedBy { +func (m *AppliedDeviceConfiguration) GetExecutedBy() isAppliedDeviceConfiguration_ExecutedBy { if m != nil { return m.ExecutedBy } return nil } -func (x *AppliedConfiguration) GetOnDemaned() bool { - if x, ok := x.GetExecutedBy().(*AppliedConfiguration_OnDemaned); ok { - return x.OnDemaned +func (x *AppliedDeviceConfiguration) GetOnDemand() bool { + if x, ok := x.GetExecutedBy().(*AppliedDeviceConfiguration_OnDemand); ok { + return x.OnDemand } return false } -func (x *AppliedConfiguration) GetConditionId() *AppliedConfiguration_RelationTo { - if x, ok := x.GetExecutedBy().(*AppliedConfiguration_ConditionId); ok { +func (x *AppliedDeviceConfiguration) GetConditionId() *AppliedDeviceConfiguration_RelationTo { + if x, ok := x.GetExecutedBy().(*AppliedDeviceConfiguration_ConditionId); ok { return x.ConditionId } return nil } -func (x *AppliedConfiguration) GetResources() []*AppliedConfiguration_Resource { +func (x *AppliedDeviceConfiguration) GetResources() []*AppliedDeviceConfiguration_Resource { if x != nil { return x.Resources } return nil } -type isAppliedConfiguration_ExecutedBy interface { - isAppliedConfiguration_ExecutedBy() +func (x *AppliedDeviceConfiguration) GetOwner() string { + if x != nil { + return x.Owner + } + return "" } -type AppliedConfiguration_OnDemaned struct { - OnDemaned bool `protobuf:"varint,4,opt,name=on_demaned,json=onDemaned,proto3,oneof"` +type isAppliedDeviceConfiguration_ExecutedBy interface { + isAppliedDeviceConfiguration_ExecutedBy() } -type AppliedConfiguration_ConditionId struct { - ConditionId *AppliedConfiguration_RelationTo `protobuf:"bytes,5,opt,name=condition_id,json=conditionId,proto3,oneof"` +type AppliedDeviceConfiguration_OnDemand struct { + OnDemand bool `protobuf:"varint,4,opt,name=on_demand,json=onDemand,proto3,oneof"` } -func (*AppliedConfiguration_OnDemaned) isAppliedConfiguration_ExecutedBy() {} +type AppliedDeviceConfiguration_ConditionId struct { + ConditionId *AppliedDeviceConfiguration_RelationTo `protobuf:"bytes,5,opt,name=condition_id,json=conditionId,proto3,oneof"` //TODO Naming +} -func (*AppliedConfiguration_ConditionId) isAppliedConfiguration_ExecutedBy() {} +func (*AppliedDeviceConfiguration_OnDemand) isAppliedDeviceConfiguration_ExecutedBy() {} + +func (*AppliedDeviceConfiguration_ConditionId) isAppliedDeviceConfiguration_ExecutedBy() {} type InvokeConfigurationRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - DeviceIdFilter []string `protobuf:"bytes,2,rep,name=device_id_filter,json=deviceIdFilter,proto3" json:"device_id_filter,omitempty"` // at least one must be set - Force bool `protobuf:"varint,3,opt,name=force,proto3" json:"force,omitempty"` // force update even if the configuration has already been applied to device - KeepUpdatingOnFailure bool `protobuf:"varint,4,opt,name=keep_updating_on_failure,json=keepUpdatingOnFailure,proto3" json:"keep_updating_on_failure,omitempty"` // if any update resource fails continue with next resource + ConfigurationId string `protobuf:"bytes,1,opt,name=configuration_id,json=configurationId,proto3" json:"configuration_id,omitempty"` // applies latest configuration + DeviceId string `protobuf:"bytes,2,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` + Force bool `protobuf:"varint,3,opt,name=force,proto3" json:"force,omitempty"` // force update even if the configuration has already been applied to device + CorrelationId string `protobuf:"bytes,4,opt,name=correlation_id,json=correlationId,proto3" json:"correlation_id,omitempty"` // propagated down to the resource update command } func (x *InvokeConfigurationRequest) Reset() { *x = InvokeConfigurationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[11] + mi := &file_snapshot_service_pb_service_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -844,7 +824,7 @@ func (x *InvokeConfigurationRequest) String() string { func (*InvokeConfigurationRequest) ProtoMessage() {} func (x *InvokeConfigurationRequest) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[11] + mi := &file_snapshot_service_pb_service_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -857,21 +837,21 @@ func (x *InvokeConfigurationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use InvokeConfigurationRequest.ProtoReflect.Descriptor instead. func (*InvokeConfigurationRequest) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{11} + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{10} } -func (x *InvokeConfigurationRequest) GetId() string { +func (x *InvokeConfigurationRequest) GetConfigurationId() string { if x != nil { - return x.Id + return x.ConfigurationId } return "" } -func (x *InvokeConfigurationRequest) GetDeviceIdFilter() []string { +func (x *InvokeConfigurationRequest) GetDeviceId() string { if x != nil { - return x.DeviceIdFilter + return x.DeviceId } - return nil + return "" } func (x *InvokeConfigurationRequest) GetForce() bool { @@ -881,41 +861,41 @@ func (x *InvokeConfigurationRequest) GetForce() bool { return false } -func (x *InvokeConfigurationRequest) GetKeepUpdatingOnFailure() bool { +func (x *InvokeConfigurationRequest) GetCorrelationId() string { if x != nil { - return x.KeepUpdatingOnFailure + return x.CorrelationId } - return false + return "" } -type GetAppliedConfigurationsRequest struct { +type GetAppliedDeviceConfigurationsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields IdFilter []string `protobuf:"bytes,1,rep,name=id_filter,json=idFilter,proto3" json:"id_filter,omitempty"` - ConfigurationIdFilter []*IdFilter `protobuf:"bytes,2,rep,name=configuration_id_filter,json=configurationIdFilter,proto3" json:"configuration_id_filter,omitempty"` + ConfigurationIdFilter []*IDFilter `protobuf:"bytes,2,rep,name=configuration_id_filter,json=configurationIdFilter,proto3" json:"configuration_id_filter,omitempty"` DeviceIdFilter []string `protobuf:"bytes,3,rep,name=device_id_filter,json=deviceIdFilter,proto3" json:"device_id_filter,omitempty"` - ConditionIdFilter []string `protobuf:"bytes,4,rep,name=condition_id_filter,json=conditionIdFilter,proto3" json:"condition_id_filter,omitempty"` + ConditionIdFilter []*IDFilter `protobuf:"bytes,4,rep,name=condition_id_filter,json=conditionIdFilter,proto3" json:"condition_id_filter,omitempty"` } -func (x *GetAppliedConfigurationsRequest) Reset() { - *x = GetAppliedConfigurationsRequest{} +func (x *GetAppliedDeviceConfigurationsRequest) Reset() { + *x = GetAppliedDeviceConfigurationsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[12] + mi := &file_snapshot_service_pb_service_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *GetAppliedConfigurationsRequest) String() string { +func (x *GetAppliedDeviceConfigurationsRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAppliedConfigurationsRequest) ProtoMessage() {} +func (*GetAppliedDeviceConfigurationsRequest) ProtoMessage() {} -func (x *GetAppliedConfigurationsRequest) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[12] +func (x *GetAppliedDeviceConfigurationsRequest) ProtoReflect() protoreflect.Message { + mi := &file_snapshot_service_pb_service_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -926,40 +906,40 @@ func (x *GetAppliedConfigurationsRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAppliedConfigurationsRequest.ProtoReflect.Descriptor instead. -func (*GetAppliedConfigurationsRequest) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{12} +// Deprecated: Use GetAppliedDeviceConfigurationsRequest.ProtoReflect.Descriptor instead. +func (*GetAppliedDeviceConfigurationsRequest) Descriptor() ([]byte, []int) { + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{11} } -func (x *GetAppliedConfigurationsRequest) GetIdFilter() []string { +func (x *GetAppliedDeviceConfigurationsRequest) GetIdFilter() []string { if x != nil { return x.IdFilter } return nil } -func (x *GetAppliedConfigurationsRequest) GetConfigurationIdFilter() []*IdFilter { +func (x *GetAppliedDeviceConfigurationsRequest) GetConfigurationIdFilter() []*IDFilter { if x != nil { return x.ConfigurationIdFilter } return nil } -func (x *GetAppliedConfigurationsRequest) GetDeviceIdFilter() []string { +func (x *GetAppliedDeviceConfigurationsRequest) GetDeviceIdFilter() []string { if x != nil { return x.DeviceIdFilter } return nil } -func (x *GetAppliedConfigurationsRequest) GetConditionIdFilter() []string { +func (x *GetAppliedDeviceConfigurationsRequest) GetConditionIdFilter() []*IDFilter { if x != nil { return x.ConditionIdFilter } return nil } -type DeleteAppliedConfigurationsRequest struct { +type DeleteAppliedDeviceConfigurationsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -967,23 +947,23 @@ type DeleteAppliedConfigurationsRequest struct { IdFilter []string `protobuf:"bytes,1,rep,name=id_filter,json=idFilter,proto3" json:"id_filter,omitempty"` } -func (x *DeleteAppliedConfigurationsRequest) Reset() { - *x = DeleteAppliedConfigurationsRequest{} +func (x *DeleteAppliedDeviceConfigurationsRequest) Reset() { + *x = DeleteAppliedDeviceConfigurationsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[13] + mi := &file_snapshot_service_pb_service_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *DeleteAppliedConfigurationsRequest) String() string { +func (x *DeleteAppliedDeviceConfigurationsRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeleteAppliedConfigurationsRequest) ProtoMessage() {} +func (*DeleteAppliedDeviceConfigurationsRequest) ProtoMessage() {} -func (x *DeleteAppliedConfigurationsRequest) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[13] +func (x *DeleteAppliedDeviceConfigurationsRequest) ProtoReflect() protoreflect.Message { + mi := &file_snapshot_service_pb_service_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -994,19 +974,19 @@ func (x *DeleteAppliedConfigurationsRequest) ProtoReflect() protoreflect.Message return mi.MessageOf(x) } -// Deprecated: Use DeleteAppliedConfigurationsRequest.ProtoReflect.Descriptor instead. -func (*DeleteAppliedConfigurationsRequest) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{13} +// Deprecated: Use DeleteAppliedDeviceConfigurationsRequest.ProtoReflect.Descriptor instead. +func (*DeleteAppliedDeviceConfigurationsRequest) Descriptor() ([]byte, []int) { + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{12} } -func (x *DeleteAppliedConfigurationsRequest) GetIdFilter() []string { +func (x *DeleteAppliedDeviceConfigurationsRequest) GetIdFilter() []string { if x != nil { return x.IdFilter } return nil } -type DeleteAppliedConfigurationsResponse struct { +type DeleteAppliedDeviceConfigurationsResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -1014,23 +994,23 @@ type DeleteAppliedConfigurationsResponse struct { Count int64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` } -func (x *DeleteAppliedConfigurationsResponse) Reset() { - *x = DeleteAppliedConfigurationsResponse{} +func (x *DeleteAppliedDeviceConfigurationsResponse) Reset() { + *x = DeleteAppliedDeviceConfigurationsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[14] + mi := &file_snapshot_service_pb_service_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *DeleteAppliedConfigurationsResponse) String() string { +func (x *DeleteAppliedDeviceConfigurationsResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeleteAppliedConfigurationsResponse) ProtoMessage() {} +func (*DeleteAppliedDeviceConfigurationsResponse) ProtoMessage() {} -func (x *DeleteAppliedConfigurationsResponse) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[14] +func (x *DeleteAppliedDeviceConfigurationsResponse) ProtoReflect() protoreflect.Message { + mi := &file_snapshot_service_pb_service_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1041,99 +1021,32 @@ func (x *DeleteAppliedConfigurationsResponse) ProtoReflect() protoreflect.Messag return mi.MessageOf(x) } -// Deprecated: Use DeleteAppliedConfigurationsResponse.ProtoReflect.Descriptor instead. -func (*DeleteAppliedConfigurationsResponse) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{14} +// Deprecated: Use DeleteAppliedDeviceConfigurationsResponse.ProtoReflect.Descriptor instead. +func (*DeleteAppliedDeviceConfigurationsResponse) Descriptor() ([]byte, []int) { + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{13} } -func (x *DeleteAppliedConfigurationsResponse) GetCount() int64 { +func (x *DeleteAppliedDeviceConfigurationsResponse) GetCount() int64 { if x != nil { return x.Count } return 0 } -type Condition_InvokeConfiguration struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // latest version of cfg - KeepUpdatingOnFailure bool `protobuf:"varint,2,opt,name=keep_updating_on_failure,json=keepUpdatingOnFailure,proto3" json:"keep_updating_on_failure,omitempty"` - ApiAccessToken string `protobuf:"bytes,3,opt,name=api_access_token,json=apiAccessToken,proto3" json:"api_access_token,omitempty"` // token used to update resources in the configuration -} - -func (x *Condition_InvokeConfiguration) Reset() { - *x = Condition_InvokeConfiguration{} - if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Condition_InvokeConfiguration) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Condition_InvokeConfiguration) ProtoMessage() {} - -func (x *Condition_InvokeConfiguration) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Condition_InvokeConfiguration.ProtoReflect.Descriptor instead. -func (*Condition_InvokeConfiguration) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{1, 0} -} - -func (x *Condition_InvokeConfiguration) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *Condition_InvokeConfiguration) GetKeepUpdatingOnFailure() bool { - if x != nil { - return x.KeepUpdatingOnFailure - } - return false -} - -func (x *Condition_InvokeConfiguration) GetApiAccessToken() string { - if x != nil { - return x.ApiAccessToken - } - return "" -} - type Configuration_Resource struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Types that are assignable to Filter: - // - // *Configuration_Resource_Href - // *Configuration_Resource_ResourceTypes - Filter isConfiguration_Resource_Filter `protobuf_oneof:"filter"` - Content *commands.Content `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` - TimeToLive int64 `protobuf:"varint,4,opt,name=time_to_live,json=timeToLive,proto3" json:"time_to_live,omitempty"` // optional update command time to live + Href string `protobuf:"bytes,1,opt,name=href,proto3" json:"href,omitempty"` + Content *commands.Content `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` + TimeToLive int64 `protobuf:"varint,4,opt,name=time_to_live,json=timeToLive,proto3" json:"time_to_live,omitempty"` // optional update command time to live, 0 is infinite } func (x *Configuration_Resource) Reset() { *x = Configuration_Resource{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[16] + mi := &file_snapshot_service_pb_service_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1146,7 +1059,7 @@ func (x *Configuration_Resource) String() string { func (*Configuration_Resource) ProtoMessage() {} func (x *Configuration_Resource) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[16] + mi := &file_snapshot_service_pb_service_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1159,30 +1072,16 @@ func (x *Configuration_Resource) ProtoReflect() protoreflect.Message { // Deprecated: Use Configuration_Resource.ProtoReflect.Descriptor instead. func (*Configuration_Resource) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{6, 0} -} - -func (m *Configuration_Resource) GetFilter() isConfiguration_Resource_Filter { - if m != nil { - return m.Filter - } - return nil + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{5, 0} } func (x *Configuration_Resource) GetHref() string { - if x, ok := x.GetFilter().(*Configuration_Resource_Href); ok { + if x != nil { return x.Href } return "" } -func (x *Configuration_Resource) GetResourceTypes() *ResourceTypes { - if x, ok := x.GetFilter().(*Configuration_Resource_ResourceTypes); ok { - return x.ResourceTypes - } - return nil -} - func (x *Configuration_Resource) GetContent() *commands.Content { if x != nil { return x.Content @@ -1197,52 +1096,34 @@ func (x *Configuration_Resource) GetTimeToLive() int64 { return 0 } -type isConfiguration_Resource_Filter interface { - isConfiguration_Resource_Filter() -} - -type Configuration_Resource_Href struct { - Href string `protobuf:"bytes,1,opt,name=href,proto3,oneof"` -} - -type Configuration_Resource_ResourceTypes struct { - ResourceTypes *ResourceTypes `protobuf:"bytes,2,opt,name=resource_types,json=resourceTypes,proto3,oneof"` -} - -func (*Configuration_Resource_Href) isConfiguration_Resource_Filter() {} - -func (*Configuration_Resource_ResourceTypes) isConfiguration_Resource_Filter() {} - -type AppliedConfiguration_Resource struct { +type AppliedDeviceConfiguration_Resource struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ResourceId *commands.ResourceId `protobuf:"bytes,1,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` - ConfigurationResourcesIdx uint32 `protobuf:"varint,2,opt,name=configuration_resources_idx,json=configurationResourcesIdx,proto3" json:"configuration_resources_idx,omitempty"` // index of resource in configuration resources array. For resource types it could be mutliple resources. - Status AppliedConfiguration_Resource_Status `protobuf:"varint,3,opt,name=status,proto3,enum=snapshotservice.pb.AppliedConfiguration_Resource_Status" json:"status,omitempty"` - TimestampStart int64 `protobuf:"varint,4,opt,name=timestamp_start,json=timestampStart,proto3" json:"timestamp_start,omitempty"` // when the rule association was applied - ValidUntil int64 `protobuf:"varint,5,opt,name=valid_until,json=validUntil,proto3" json:"valid_until,omitempty"` // how long the command is valid - ResourceUpdated *events.ResourceUpdated `protobuf:"bytes,6,opt,name=resource_updated,json=resourceUpdated,proto3" json:"resource_updated,omitempty"` + ResourceId *commands.ResourceId `protobuf:"bytes,1,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` // TODO Jozo href only? + CorrelationId string `protobuf:"bytes,2,opt,name=correlation_id,json=correlationId,proto3" json:"correlation_id,omitempty"` // Reused from invoke command or generated. Can be used to retrieve corresponding pending command. + Status AppliedDeviceConfiguration_Resource_Status `protobuf:"varint,3,opt,name=status,proto3,enum=snapshotservice.pb.AppliedDeviceConfiguration_Resource_Status" json:"status,omitempty"` + ResourceUpdated *events.ResourceUpdated `protobuf:"bytes,4,opt,name=resource_updated,json=resourceUpdated,proto3" json:"resource_updated,omitempty"` } -func (x *AppliedConfiguration_Resource) Reset() { - *x = AppliedConfiguration_Resource{} +func (x *AppliedDeviceConfiguration_Resource) Reset() { + *x = AppliedDeviceConfiguration_Resource{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[17] + mi := &file_snapshot_service_pb_service_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *AppliedConfiguration_Resource) String() string { +func (x *AppliedDeviceConfiguration_Resource) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AppliedConfiguration_Resource) ProtoMessage() {} +func (*AppliedDeviceConfiguration_Resource) ProtoMessage() {} -func (x *AppliedConfiguration_Resource) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[17] +func (x *AppliedDeviceConfiguration_Resource) ProtoReflect() protoreflect.Message { + mi := &file_snapshot_service_pb_service_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1253,54 +1134,40 @@ func (x *AppliedConfiguration_Resource) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use AppliedConfiguration_Resource.ProtoReflect.Descriptor instead. -func (*AppliedConfiguration_Resource) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{10, 0} +// Deprecated: Use AppliedDeviceConfiguration_Resource.ProtoReflect.Descriptor instead. +func (*AppliedDeviceConfiguration_Resource) Descriptor() ([]byte, []int) { + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{9, 0} } -func (x *AppliedConfiguration_Resource) GetResourceId() *commands.ResourceId { +func (x *AppliedDeviceConfiguration_Resource) GetResourceId() *commands.ResourceId { if x != nil { return x.ResourceId } return nil } -func (x *AppliedConfiguration_Resource) GetConfigurationResourcesIdx() uint32 { +func (x *AppliedDeviceConfiguration_Resource) GetCorrelationId() string { if x != nil { - return x.ConfigurationResourcesIdx + return x.CorrelationId } - return 0 + return "" } -func (x *AppliedConfiguration_Resource) GetStatus() AppliedConfiguration_Resource_Status { +func (x *AppliedDeviceConfiguration_Resource) GetStatus() AppliedDeviceConfiguration_Resource_Status { if x != nil { return x.Status } - return AppliedConfiguration_Resource_QUEUED -} - -func (x *AppliedConfiguration_Resource) GetTimestampStart() int64 { - if x != nil { - return x.TimestampStart - } - return 0 -} - -func (x *AppliedConfiguration_Resource) GetValidUntil() int64 { - if x != nil { - return x.ValidUntil - } - return 0 + return AppliedDeviceConfiguration_Resource_QUEUED } -func (x *AppliedConfiguration_Resource) GetResourceUpdated() *events.ResourceUpdated { +func (x *AppliedDeviceConfiguration_Resource) GetResourceUpdated() *events.ResourceUpdated { if x != nil { return x.ResourceUpdated } return nil } -type AppliedConfiguration_RelationTo struct { +type AppliedDeviceConfiguration_RelationTo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -1309,23 +1176,23 @@ type AppliedConfiguration_RelationTo struct { Version uint64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` } -func (x *AppliedConfiguration_RelationTo) Reset() { - *x = AppliedConfiguration_RelationTo{} +func (x *AppliedDeviceConfiguration_RelationTo) Reset() { + *x = AppliedDeviceConfiguration_RelationTo{} if protoimpl.UnsafeEnabled { - mi := &file_snapshot_service_pb_service_proto_msgTypes[18] + mi := &file_snapshot_service_pb_service_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *AppliedConfiguration_RelationTo) String() string { +func (x *AppliedDeviceConfiguration_RelationTo) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AppliedConfiguration_RelationTo) ProtoMessage() {} +func (*AppliedDeviceConfiguration_RelationTo) ProtoMessage() {} -func (x *AppliedConfiguration_RelationTo) ProtoReflect() protoreflect.Message { - mi := &file_snapshot_service_pb_service_proto_msgTypes[18] +func (x *AppliedDeviceConfiguration_RelationTo) ProtoReflect() protoreflect.Message { + mi := &file_snapshot_service_pb_service_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1336,19 +1203,19 @@ func (x *AppliedConfiguration_RelationTo) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use AppliedConfiguration_RelationTo.ProtoReflect.Descriptor instead. -func (*AppliedConfiguration_RelationTo) Descriptor() ([]byte, []int) { - return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{10, 1} +// Deprecated: Use AppliedDeviceConfiguration_RelationTo.ProtoReflect.Descriptor instead. +func (*AppliedDeviceConfiguration_RelationTo) Descriptor() ([]byte, []int) { + return file_snapshot_service_pb_service_proto_rawDescGZIP(), []int{9, 1} } -func (x *AppliedConfiguration_RelationTo) GetId() string { +func (x *AppliedDeviceConfiguration_RelationTo) GetId() string { if x != nil { return x.Id } return "" } -func (x *AppliedConfiguration_RelationTo) GetVersion() uint64 { +func (x *AppliedDeviceConfiguration_RelationTo) GetVersion() uint64 { if x != nil { return x.Version } @@ -1371,324 +1238,309 @@ var file_snapshot_service_pb_service_proto_rawDesc = []byte{ 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x65, 0x0a, 0x08, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, + 0x22, 0x6b, 0x0a, 0x08, 0x49, 0x44, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x08, 0x48, 0x00, 0x52, 0x03, 0x61, 0x6c, 0x6c, 0x12, 0x12, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x42, 0x09, 0x0a, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x87, 0x04, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x64, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x28, 0x0a, - 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, - 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, - 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, - 0x79, 0x70, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x68, 0x72, 0x65, 0x66, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x48, 0x72, 0x65, 0x66, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x79, - 0x71, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0c, 0x79, 0x71, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x64, 0x0a, 0x14, 0x69, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, - 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x6e, - 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x13, 0x69, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x88, 0x01, 0x0a, 0x13, 0x49, 0x6e, 0x76, 0x6f, 0x6b, - 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x37, - 0x0a, 0x18, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, - 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x15, 0x6b, 0x65, 0x65, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x6e, - 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x61, 0x70, 0x69, 0x5f, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x61, 0x70, 0x69, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x22, 0x51, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x09, 0x69, 0x64, 0x5f, - 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x08, 0x69, 0x64, 0x46, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x22, 0x54, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, - 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x39, 0x0a, 0x09, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x52, 0x08, 0x69, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x30, 0x0a, 0x18, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x37, 0x0a, 0x0d, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x14, 0x0a, - 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x22, 0xeb, 0x02, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x48, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, - 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x1a, - 0xd1, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x04, - 0x68, 0x72, 0x65, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x68, 0x72, - 0x65, 0x66, 0x12, 0x4a, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x48, 0x00, 0x52, - 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x37, - 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, - 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, - 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, - 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x66, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x22, 0x55, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x39, 0x0a, 0x09, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x52, 0x08, 0x69, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x58, 0x0a, 0x1b, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x09, 0x69, 0x64, 0x5f, - 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, + 0x08, 0x48, 0x00, 0x52, 0x03, 0x61, 0x6c, 0x6c, 0x12, 0x18, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x8e, 0x03, + 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x28, + 0x0a, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x68, 0x72, 0x65, 0x66, 0x5f, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x48, 0x72, 0x65, 0x66, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x14, + 0x6a, 0x71, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6a, 0x71, 0x45, 0x78, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, + 0x0a, 0x10, 0x61, 0x70, 0x69, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x70, 0x69, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, + 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x22, 0x51, + 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x09, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x49, + 0x44, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x08, 0x69, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x22, 0x54, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x09, + 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x44, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x08, 0x69, + 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x30, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xa8, 0x02, 0x0a, 0x0d, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x48, 0x0a, 0x09, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x08, 0x69, 0x64, 0x46, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x22, 0x34, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x94, 0x07, 0x0a, 0x14, 0x41, - 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, - 0x12, 0x5e, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x73, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x52, - 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x1f, 0x0a, 0x0a, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x65, 0x64, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x6f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x65, - 0x64, 0x12, 0x58, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, - 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, - 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, - 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x48, 0x00, 0x52, 0x0b, - 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x4f, 0x0a, 0x09, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, - 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x1a, 0xdb, 0x03, 0x0a, - 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, - 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, - 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x3e, 0x0a, 0x1b, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x5f, 0x69, 0x64, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x19, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x49, 0x64, 0x78, 0x12, 0x50, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x38, 0x2e, 0x73, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x27, - 0x0a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, - 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x50, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, + 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x1a, 0x79, 0x0a, 0x08, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x72, 0x65, 0x66, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x72, 0x65, 0x66, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, + 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, + 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, + 0x4c, 0x69, 0x76, 0x65, 0x22, 0x55, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x39, 0x0a, 0x09, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x44, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x52, 0x08, 0x69, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x58, 0x0a, 0x1b, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x09, 0x69, 0x64, + 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x49, 0x44, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x08, 0x69, 0x64, 0x46, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x34, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xbd, 0x06, 0x0a, 0x1a, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x64, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x52, 0x0f, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, + 0x09, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x48, 0x00, 0x52, 0x08, 0x6f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x5e, 0x0a, 0x0c, + 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x48, 0x00, 0x52, + 0x0b, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x55, 0x0a, 0x09, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x37, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x1a, 0xd8, 0x02, 0x0a, 0x08, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, + 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x56, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x3e, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x50, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x22, 0x5e, 0x0a, 0x06, 0x53, 0x74, + 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x22, 0x38, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0a, 0x0a, 0x06, 0x51, 0x55, 0x45, 0x55, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x4e, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, - 0x12, 0x17, 0x0a, 0x13, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x46, 0x4f, 0x52, 0x5f, - 0x52, 0x45, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x4f, 0x4e, - 0x45, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x04, - 0x12, 0x08, 0x0a, 0x04, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x05, 0x1a, 0x36, 0x0a, 0x0a, 0x52, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x62, - 0x79, 0x22, 0xa5, 0x01, 0x0a, 0x1a, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, - 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, - 0x12, 0x37, 0x0a, 0x18, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, - 0x67, 0x5f, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x15, 0x6b, 0x65, 0x65, 0x70, 0x55, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, - 0x4f, 0x6e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x22, 0xee, 0x01, 0x0a, 0x1f, 0x47, 0x65, - 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, - 0x09, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x08, 0x69, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x17, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x5f, 0x66, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x15, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x6f, - 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x41, 0x0a, 0x22, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, + 0x04, 0x44, 0x4f, 0x4e, 0x45, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x49, 0x4d, 0x45, 0x4f, + 0x55, 0x54, 0x10, 0x03, 0x1a, 0x36, 0x0a, 0x0a, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x22, 0xa1, 0x01, 0x0a, 0x1a, + 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, + 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, + 0x92, 0x02, 0x0a, 0x25, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x64, 0x5f, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x17, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x44, 0x46, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x15, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x4c, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x44, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x22, 0x47, 0x0a, 0x28, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x3b, 0x0a, - 0x23, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0xe4, 0x0d, 0x0a, 0x0f, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7d, - 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x1d, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x1a, 0x1d, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x2c, 0x92, 0x41, 0x0c, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x01, 0x2a, 0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x85, 0x01, - 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x28, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x73, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, - 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x92, 0x41, 0x0c, 0x0a, 0x0a, 0x43, - 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, + 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x41, 0x0a, + 0x29, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x32, 0x90, 0x0e, 0x0a, 0x0f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x7d, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, + 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1d, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x92, 0x41, 0x0c, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, 0x01, 0x2a, 0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x30, 0x01, 0x12, 0x98, 0x01, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x2e, 0x73, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x6f, 0x6e, 0x73, 0x12, 0x85, 0x01, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x28, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1d, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x29, + 0x92, 0x41, 0x0c, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x30, 0x01, 0x12, 0x98, 0x01, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, - 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x92, 0x41, 0x0c, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x64, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x2a, 0x12, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x82, 0x01, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x1a, 0x1d, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x22, 0x31, 0x92, 0x41, 0x0c, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x3a, 0x01, 0x2a, 0x1a, 0x17, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x91, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x2e, + 0x12, 0x2b, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x1a, 0x21, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0x34, 0x92, 0x41, 0x10, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x3a, 0x01, - 0x2a, 0x22, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x99, 0x01, 0x0a, 0x11, 0x47, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x2c, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, - 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x31, 0x92, 0x41, 0x10, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x30, 0x01, 0x12, 0xac, 0x01, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, - 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x30, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x31, 0x92, 0x41, 0x10, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x96, 0x01, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x2e, 0x73, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, - 0x21, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x22, 0x39, 0x92, 0x41, 0x10, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, - 0x1a, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0xac, 0x01, - 0x0a, 0x13, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, - 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x39, 0x92, 0x41, 0x10, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x30, 0x01, 0x12, 0xb6, 0x01, 0x0a, - 0x18, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x33, 0x2e, 0x73, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, - 0x65, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, - 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x92, 0x41, 0x0c, + 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x14, 0x2a, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x82, 0x01, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x2e, 0x73, 0x6e, 0x61, + 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1d, 0x2e, 0x73, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x31, 0x92, 0x41, 0x0c, 0x0a, 0x0a, 0x43, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x3a, + 0x01, 0x2a, 0x1a, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x91, 0x01, 0x0a, 0x13, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x21, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x34, 0x92, 0x41, 0x10, 0x0a, 0x0e, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1b, 0x3a, 0x01, 0x2a, 0x22, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x99, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2c, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x31, 0x92, 0x41, 0x10, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x18, 0x12, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x30, 0x01, 0x12, 0xac, 0x01, 0x0a, 0x14, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x92, 0x41, 0x10, 0x0a, 0x0e, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x96, 0x01, 0x0a, 0x13, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x21, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x21, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x39, 0x92, 0x41, 0x10, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, + 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x1a, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, + 0x69, 0x64, 0x7d, 0x12, 0xc0, 0x01, 0x0a, 0x13, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x73, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x73, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x47, 0x92, 0x41, 0x10, + 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x3a, 0x01, 0x2a, 0x22, 0x29, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2f, 0x7b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x7d, 0x30, 0x01, 0x12, 0xc2, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x39, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, + 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x39, + 0x92, 0x41, 0x10, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x30, 0x01, 0x12, 0xd5, 0x01, 0x0a, 0x1b, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3c, 0x2e, 0x73, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x73, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0x92, 0x41, 0x10, 0x0a, 0x0e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x20, 0x2a, 0x1e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x70, 0x70, 0x6c, - 0x69, 0x65, 0x64, 0x30, 0x01, 0x12, 0xc9, 0x01, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x36, 0x2e, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, - 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0x92, 0x41, 0x10, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x20, 0x2a, 0x1e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, - 0x64, 0x42, 0xd6, 0x02, 0x92, 0x41, 0x9f, 0x02, 0x12, 0xc7, 0x01, 0x0a, 0x14, 0x50, 0x4c, 0x47, - 0x44, 0x20, 0x52, 0x75, 0x6c, 0x65, 0x20, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x50, - 0x49, 0x12, 0x27, 0x41, 0x50, 0x49, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x20, 0x65, 0x6e, 0x67, 0x69, - 0x6e, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x50, 0x4c, 0x47, 0x44, 0x22, 0x3a, 0x0a, 0x08, 0x70, 0x6c, - 0x67, 0x64, 0x2e, 0x64, 0x65, 0x76, 0x12, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d, - 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x1a, 0x0d, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x70, 0x6c, - 0x67, 0x64, 0x2e, 0x64, 0x65, 0x76, 0x2a, 0x45, 0x0a, 0x12, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, - 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x32, 0x2e, 0x30, 0x12, 0x2f, 0x68, 0x74, - 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x2f, 0x62, 0x6c, - 0x6f, 0x62, 0x2f, 0x76, 0x32, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x03, 0x31, - 0x2e, 0x30, 0x2a, 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x32, 0x15, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, - 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, - 0x3a, 0x15, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x6a, 0x73, 0x6f, 0x6e, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, - 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x2d, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x2f, 0x70, 0x62, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x69, 0x65, 0x64, 0x42, 0xd6, 0x02, 0x92, 0x41, 0x9f, 0x02, 0x12, 0xc7, 0x01, 0x0a, 0x14, 0x50, + 0x4c, 0x47, 0x44, 0x20, 0x52, 0x75, 0x6c, 0x65, 0x20, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x20, + 0x41, 0x50, 0x49, 0x12, 0x27, 0x41, 0x50, 0x49, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x20, 0x65, 0x6e, + 0x67, 0x69, 0x6e, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x50, 0x4c, 0x47, 0x44, 0x22, 0x3a, 0x0a, 0x08, + 0x70, 0x6c, 0x67, 0x64, 0x2e, 0x64, 0x65, 0x76, 0x12, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, + 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67, + 0x64, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x1a, 0x0d, 0x69, 0x6e, 0x66, 0x6f, 0x40, + 0x70, 0x6c, 0x67, 0x64, 0x2e, 0x64, 0x65, 0x76, 0x2a, 0x45, 0x0a, 0x12, 0x41, 0x70, 0x61, 0x63, + 0x68, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x32, 0x2e, 0x30, 0x12, 0x2f, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x2f, + 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x76, 0x32, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, + 0x03, 0x31, 0x2e, 0x30, 0x2a, 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x32, 0x15, 0x61, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6a, 0x73, 0x6f, 0x6e, + 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, + 0x6f, 0x6e, 0x3a, 0x15, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6a, 0x73, 0x6f, 0x6e, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, + 0x75, 0x62, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x2d, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x70, 0x62, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1704,75 +1556,72 @@ func file_snapshot_service_pb_service_proto_rawDescGZIP() []byte { } var file_snapshot_service_pb_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_snapshot_service_pb_service_proto_msgTypes = make([]protoimpl.MessageInfo, 19) +var file_snapshot_service_pb_service_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_snapshot_service_pb_service_proto_goTypes = []interface{}{ - (AppliedConfiguration_Resource_Status)(0), // 0: snapshotservice.pb.AppliedConfiguration.Resource.Status - (*IdFilter)(nil), // 1: snapshotservice.pb.IdFilter - (*Condition)(nil), // 2: snapshotservice.pb.Condition - (*GetConditionsRequest)(nil), // 3: snapshotservice.pb.GetConditionsRequest - (*DeleteConditionsRequest)(nil), // 4: snapshotservice.pb.DeleteConditionsRequest - (*DeleteConditionsResponse)(nil), // 5: snapshotservice.pb.DeleteConditionsResponse - (*ResourceTypes)(nil), // 6: snapshotservice.pb.ResourceTypes - (*Configuration)(nil), // 7: snapshotservice.pb.Configuration - (*GetConfigurationsRequest)(nil), // 8: snapshotservice.pb.GetConfigurationsRequest - (*DeleteConfigurationsRequest)(nil), // 9: snapshotservice.pb.DeleteConfigurationsRequest - (*DeleteConfigurationsResponse)(nil), // 10: snapshotservice.pb.DeleteConfigurationsResponse - (*AppliedConfiguration)(nil), // 11: snapshotservice.pb.AppliedConfiguration - (*InvokeConfigurationRequest)(nil), // 12: snapshotservice.pb.InvokeConfigurationRequest - (*GetAppliedConfigurationsRequest)(nil), // 13: snapshotservice.pb.GetAppliedConfigurationsRequest - (*DeleteAppliedConfigurationsRequest)(nil), // 14: snapshotservice.pb.DeleteAppliedConfigurationsRequest - (*DeleteAppliedConfigurationsResponse)(nil), // 15: snapshotservice.pb.DeleteAppliedConfigurationsResponse - (*Condition_InvokeConfiguration)(nil), // 16: snapshotservice.pb.Condition.InvokeConfiguration - (*Configuration_Resource)(nil), // 17: snapshotservice.pb.Configuration.Resource - (*AppliedConfiguration_Resource)(nil), // 18: snapshotservice.pb.AppliedConfiguration.Resource - (*AppliedConfiguration_RelationTo)(nil), // 19: snapshotservice.pb.AppliedConfiguration.RelationTo - (*commands.Content)(nil), // 20: resourceaggregate.pb.Content - (*commands.ResourceId)(nil), // 21: resourceaggregate.pb.ResourceId - (*events.ResourceUpdated)(nil), // 22: resourceaggregate.pb.ResourceUpdated + (AppliedDeviceConfiguration_Resource_Status)(0), // 0: snapshotservice.pb.AppliedDeviceConfiguration.Resource.Status + (*IDFilter)(nil), // 1: snapshotservice.pb.IDFilter + (*Condition)(nil), // 2: snapshotservice.pb.Condition + (*GetConditionsRequest)(nil), // 3: snapshotservice.pb.GetConditionsRequest + (*DeleteConditionsRequest)(nil), // 4: snapshotservice.pb.DeleteConditionsRequest + (*DeleteConditionsResponse)(nil), // 5: snapshotservice.pb.DeleteConditionsResponse + (*Configuration)(nil), // 6: snapshotservice.pb.Configuration + (*GetConfigurationsRequest)(nil), // 7: snapshotservice.pb.GetConfigurationsRequest + (*DeleteConfigurationsRequest)(nil), // 8: snapshotservice.pb.DeleteConfigurationsRequest + (*DeleteConfigurationsResponse)(nil), // 9: snapshotservice.pb.DeleteConfigurationsResponse + (*AppliedDeviceConfiguration)(nil), // 10: snapshotservice.pb.AppliedDeviceConfiguration + (*InvokeConfigurationRequest)(nil), // 11: snapshotservice.pb.InvokeConfigurationRequest + (*GetAppliedDeviceConfigurationsRequest)(nil), // 12: snapshotservice.pb.GetAppliedDeviceConfigurationsRequest + (*DeleteAppliedDeviceConfigurationsRequest)(nil), // 13: snapshotservice.pb.DeleteAppliedDeviceConfigurationsRequest + (*DeleteAppliedDeviceConfigurationsResponse)(nil), // 14: snapshotservice.pb.DeleteAppliedDeviceConfigurationsResponse + (*Configuration_Resource)(nil), // 15: snapshotservice.pb.Configuration.Resource + (*AppliedDeviceConfiguration_Resource)(nil), // 16: snapshotservice.pb.AppliedDeviceConfiguration.Resource + (*AppliedDeviceConfiguration_RelationTo)(nil), // 17: snapshotservice.pb.AppliedDeviceConfiguration.RelationTo + (*commands.Content)(nil), // 18: resourceaggregate.pb.Content + (*commands.ResourceId)(nil), // 19: resourceaggregate.pb.ResourceId + (*events.ResourceUpdated)(nil), // 20: resourceaggregate.pb.ResourceUpdated } var file_snapshot_service_pb_service_proto_depIdxs = []int32{ - 16, // 0: snapshotservice.pb.Condition.invoke_configuration:type_name -> snapshotservice.pb.Condition.InvokeConfiguration - 1, // 1: snapshotservice.pb.GetConditionsRequest.id_filter:type_name -> snapshotservice.pb.IdFilter - 1, // 2: snapshotservice.pb.DeleteConditionsRequest.id_filter:type_name -> snapshotservice.pb.IdFilter - 17, // 3: snapshotservice.pb.Configuration.resources:type_name -> snapshotservice.pb.Configuration.Resource - 1, // 4: snapshotservice.pb.GetConfigurationsRequest.id_filter:type_name -> snapshotservice.pb.IdFilter - 1, // 5: snapshotservice.pb.DeleteConfigurationsRequest.id_filter:type_name -> snapshotservice.pb.IdFilter - 19, // 6: snapshotservice.pb.AppliedConfiguration.configuration_id:type_name -> snapshotservice.pb.AppliedConfiguration.RelationTo - 19, // 7: snapshotservice.pb.AppliedConfiguration.condition_id:type_name -> snapshotservice.pb.AppliedConfiguration.RelationTo - 18, // 8: snapshotservice.pb.AppliedConfiguration.resources:type_name -> snapshotservice.pb.AppliedConfiguration.Resource - 1, // 9: snapshotservice.pb.GetAppliedConfigurationsRequest.configuration_id_filter:type_name -> snapshotservice.pb.IdFilter - 6, // 10: snapshotservice.pb.Configuration.Resource.resource_types:type_name -> snapshotservice.pb.ResourceTypes - 20, // 11: snapshotservice.pb.Configuration.Resource.content:type_name -> resourceaggregate.pb.Content - 21, // 12: snapshotservice.pb.AppliedConfiguration.Resource.resource_id:type_name -> resourceaggregate.pb.ResourceId - 0, // 13: snapshotservice.pb.AppliedConfiguration.Resource.status:type_name -> snapshotservice.pb.AppliedConfiguration.Resource.Status - 22, // 14: snapshotservice.pb.AppliedConfiguration.Resource.resource_updated:type_name -> resourceaggregate.pb.ResourceUpdated - 2, // 15: snapshotservice.pb.SnapshotService.CreateCondition:input_type -> snapshotservice.pb.Condition - 3, // 16: snapshotservice.pb.SnapshotService.GetConditions:input_type -> snapshotservice.pb.GetConditionsRequest - 4, // 17: snapshotservice.pb.SnapshotService.DeleteConditions:input_type -> snapshotservice.pb.DeleteConditionsRequest - 2, // 18: snapshotservice.pb.SnapshotService.UpdateCondition:input_type -> snapshotservice.pb.Condition - 7, // 19: snapshotservice.pb.SnapshotService.CreateConfiguration:input_type -> snapshotservice.pb.Configuration - 8, // 20: snapshotservice.pb.SnapshotService.GetConfigurations:input_type -> snapshotservice.pb.GetConfigurationsRequest - 9, // 21: snapshotservice.pb.SnapshotService.DeleteConfigurations:input_type -> snapshotservice.pb.DeleteConfigurationsRequest - 7, // 22: snapshotservice.pb.SnapshotService.UpdateConfiguration:input_type -> snapshotservice.pb.Configuration - 12, // 23: snapshotservice.pb.SnapshotService.InvokeConfiguration:input_type -> snapshotservice.pb.InvokeConfigurationRequest - 13, // 24: snapshotservice.pb.SnapshotService.GetAppliedConfigurations:input_type -> snapshotservice.pb.GetAppliedConfigurationsRequest - 14, // 25: snapshotservice.pb.SnapshotService.DeleteAppliedConfigurations:input_type -> snapshotservice.pb.DeleteAppliedConfigurationsRequest - 2, // 26: snapshotservice.pb.SnapshotService.CreateCondition:output_type -> snapshotservice.pb.Condition - 2, // 27: snapshotservice.pb.SnapshotService.GetConditions:output_type -> snapshotservice.pb.Condition - 5, // 28: snapshotservice.pb.SnapshotService.DeleteConditions:output_type -> snapshotservice.pb.DeleteConditionsResponse - 2, // 29: snapshotservice.pb.SnapshotService.UpdateCondition:output_type -> snapshotservice.pb.Condition - 7, // 30: snapshotservice.pb.SnapshotService.CreateConfiguration:output_type -> snapshotservice.pb.Configuration - 7, // 31: snapshotservice.pb.SnapshotService.GetConfigurations:output_type -> snapshotservice.pb.Configuration - 10, // 32: snapshotservice.pb.SnapshotService.DeleteConfigurations:output_type -> snapshotservice.pb.DeleteConfigurationsResponse - 7, // 33: snapshotservice.pb.SnapshotService.UpdateConfiguration:output_type -> snapshotservice.pb.Configuration - 11, // 34: snapshotservice.pb.SnapshotService.InvokeConfiguration:output_type -> snapshotservice.pb.AppliedConfiguration - 11, // 35: snapshotservice.pb.SnapshotService.GetAppliedConfigurations:output_type -> snapshotservice.pb.AppliedConfiguration - 15, // 36: snapshotservice.pb.SnapshotService.DeleteAppliedConfigurations:output_type -> snapshotservice.pb.DeleteAppliedConfigurationsResponse - 26, // [26:37] is the sub-list for method output_type - 15, // [15:26] is the sub-list for method input_type - 15, // [15:15] is the sub-list for extension type_name - 15, // [15:15] is the sub-list for extension extendee - 0, // [0:15] is the sub-list for field type_name + 1, // 0: snapshotservice.pb.GetConditionsRequest.id_filter:type_name -> snapshotservice.pb.IDFilter + 1, // 1: snapshotservice.pb.DeleteConditionsRequest.id_filter:type_name -> snapshotservice.pb.IDFilter + 15, // 2: snapshotservice.pb.Configuration.resources:type_name -> snapshotservice.pb.Configuration.Resource + 1, // 3: snapshotservice.pb.GetConfigurationsRequest.id_filter:type_name -> snapshotservice.pb.IDFilter + 1, // 4: snapshotservice.pb.DeleteConfigurationsRequest.id_filter:type_name -> snapshotservice.pb.IDFilter + 17, // 5: snapshotservice.pb.AppliedDeviceConfiguration.configuration_id:type_name -> snapshotservice.pb.AppliedDeviceConfiguration.RelationTo + 17, // 6: snapshotservice.pb.AppliedDeviceConfiguration.condition_id:type_name -> snapshotservice.pb.AppliedDeviceConfiguration.RelationTo + 16, // 7: snapshotservice.pb.AppliedDeviceConfiguration.resources:type_name -> snapshotservice.pb.AppliedDeviceConfiguration.Resource + 1, // 8: snapshotservice.pb.GetAppliedDeviceConfigurationsRequest.configuration_id_filter:type_name -> snapshotservice.pb.IDFilter + 1, // 9: snapshotservice.pb.GetAppliedDeviceConfigurationsRequest.condition_id_filter:type_name -> snapshotservice.pb.IDFilter + 18, // 10: snapshotservice.pb.Configuration.Resource.content:type_name -> resourceaggregate.pb.Content + 19, // 11: snapshotservice.pb.AppliedDeviceConfiguration.Resource.resource_id:type_name -> resourceaggregate.pb.ResourceId + 0, // 12: snapshotservice.pb.AppliedDeviceConfiguration.Resource.status:type_name -> snapshotservice.pb.AppliedDeviceConfiguration.Resource.Status + 20, // 13: snapshotservice.pb.AppliedDeviceConfiguration.Resource.resource_updated:type_name -> resourceaggregate.pb.ResourceUpdated + 2, // 14: snapshotservice.pb.SnapshotService.CreateCondition:input_type -> snapshotservice.pb.Condition + 3, // 15: snapshotservice.pb.SnapshotService.GetConditions:input_type -> snapshotservice.pb.GetConditionsRequest + 4, // 16: snapshotservice.pb.SnapshotService.DeleteConditions:input_type -> snapshotservice.pb.DeleteConditionsRequest + 2, // 17: snapshotservice.pb.SnapshotService.UpdateCondition:input_type -> snapshotservice.pb.Condition + 6, // 18: snapshotservice.pb.SnapshotService.CreateConfiguration:input_type -> snapshotservice.pb.Configuration + 7, // 19: snapshotservice.pb.SnapshotService.GetConfigurations:input_type -> snapshotservice.pb.GetConfigurationsRequest + 8, // 20: snapshotservice.pb.SnapshotService.DeleteConfigurations:input_type -> snapshotservice.pb.DeleteConfigurationsRequest + 6, // 21: snapshotservice.pb.SnapshotService.UpdateConfiguration:input_type -> snapshotservice.pb.Configuration + 11, // 22: snapshotservice.pb.SnapshotService.InvokeConfiguration:input_type -> snapshotservice.pb.InvokeConfigurationRequest + 12, // 23: snapshotservice.pb.SnapshotService.GetAppliedConfigurations:input_type -> snapshotservice.pb.GetAppliedDeviceConfigurationsRequest + 13, // 24: snapshotservice.pb.SnapshotService.DeleteAppliedConfigurations:input_type -> snapshotservice.pb.DeleteAppliedDeviceConfigurationsRequest + 2, // 25: snapshotservice.pb.SnapshotService.CreateCondition:output_type -> snapshotservice.pb.Condition + 2, // 26: snapshotservice.pb.SnapshotService.GetConditions:output_type -> snapshotservice.pb.Condition + 5, // 27: snapshotservice.pb.SnapshotService.DeleteConditions:output_type -> snapshotservice.pb.DeleteConditionsResponse + 2, // 28: snapshotservice.pb.SnapshotService.UpdateCondition:output_type -> snapshotservice.pb.Condition + 6, // 29: snapshotservice.pb.SnapshotService.CreateConfiguration:output_type -> snapshotservice.pb.Configuration + 6, // 30: snapshotservice.pb.SnapshotService.GetConfigurations:output_type -> snapshotservice.pb.Configuration + 9, // 31: snapshotservice.pb.SnapshotService.DeleteConfigurations:output_type -> snapshotservice.pb.DeleteConfigurationsResponse + 6, // 32: snapshotservice.pb.SnapshotService.UpdateConfiguration:output_type -> snapshotservice.pb.Configuration + 10, // 33: snapshotservice.pb.SnapshotService.InvokeConfiguration:output_type -> snapshotservice.pb.AppliedDeviceConfiguration + 10, // 34: snapshotservice.pb.SnapshotService.GetAppliedConfigurations:output_type -> snapshotservice.pb.AppliedDeviceConfiguration + 14, // 35: snapshotservice.pb.SnapshotService.DeleteAppliedConfigurations:output_type -> snapshotservice.pb.DeleteAppliedDeviceConfigurationsResponse + 25, // [25:36] is the sub-list for method output_type + 14, // [14:25] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name } func init() { file_snapshot_service_pb_service_proto_init() } @@ -1782,7 +1631,7 @@ func file_snapshot_service_pb_service_proto_init() { } if !protoimpl.UnsafeEnabled { file_snapshot_service_pb_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IdFilter); i { + switch v := v.(*IDFilter); i { case 0: return &v.state case 1: @@ -1842,7 +1691,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResourceTypes); i { + switch v := v.(*Configuration); i { case 0: return &v.state case 1: @@ -1854,7 +1703,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Configuration); i { + switch v := v.(*GetConfigurationsRequest); i { case 0: return &v.state case 1: @@ -1866,7 +1715,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetConfigurationsRequest); i { + switch v := v.(*DeleteConfigurationsRequest); i { case 0: return &v.state case 1: @@ -1878,7 +1727,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteConfigurationsRequest); i { + switch v := v.(*DeleteConfigurationsResponse); i { case 0: return &v.state case 1: @@ -1890,7 +1739,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteConfigurationsResponse); i { + switch v := v.(*AppliedDeviceConfiguration); i { case 0: return &v.state case 1: @@ -1902,7 +1751,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AppliedConfiguration); i { + switch v := v.(*InvokeConfigurationRequest); i { case 0: return &v.state case 1: @@ -1914,7 +1763,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InvokeConfigurationRequest); i { + switch v := v.(*GetAppliedDeviceConfigurationsRequest); i { case 0: return &v.state case 1: @@ -1926,7 +1775,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetAppliedConfigurationsRequest); i { + switch v := v.(*DeleteAppliedDeviceConfigurationsRequest); i { case 0: return &v.state case 1: @@ -1938,7 +1787,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteAppliedConfigurationsRequest); i { + switch v := v.(*DeleteAppliedDeviceConfigurationsResponse); i { case 0: return &v.state case 1: @@ -1950,7 +1799,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteAppliedConfigurationsResponse); i { + switch v := v.(*Configuration_Resource); i { case 0: return &v.state case 1: @@ -1962,7 +1811,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Condition_InvokeConfiguration); i { + switch v := v.(*AppliedDeviceConfiguration_Resource); i { case 0: return &v.state case 1: @@ -1974,31 +1823,7 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Configuration_Resource); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_snapshot_service_pb_service_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AppliedConfiguration_Resource); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_snapshot_service_pb_service_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AppliedConfiguration_RelationTo); i { + switch v := v.(*AppliedDeviceConfiguration_RelationTo); i { case 0: return &v.state case 1: @@ -2011,17 +1836,13 @@ func file_snapshot_service_pb_service_proto_init() { } } file_snapshot_service_pb_service_proto_msgTypes[0].OneofWrappers = []interface{}{ - (*IdFilter_Value)(nil), - (*IdFilter_All)(nil), - (*IdFilter_Max)(nil), - } - file_snapshot_service_pb_service_proto_msgTypes[10].OneofWrappers = []interface{}{ - (*AppliedConfiguration_OnDemaned)(nil), - (*AppliedConfiguration_ConditionId)(nil), + (*IDFilter_Value)(nil), + (*IDFilter_All)(nil), + (*IDFilter_Latest)(nil), } - file_snapshot_service_pb_service_proto_msgTypes[16].OneofWrappers = []interface{}{ - (*Configuration_Resource_Href)(nil), - (*Configuration_Resource_ResourceTypes)(nil), + file_snapshot_service_pb_service_proto_msgTypes[9].OneofWrappers = []interface{}{ + (*AppliedDeviceConfiguration_OnDemand)(nil), + (*AppliedDeviceConfiguration_ConditionId)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -2029,7 +1850,7 @@ func file_snapshot_service_pb_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_snapshot_service_pb_service_proto_rawDesc, NumEnums: 1, - NumMessages: 19, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, diff --git a/snapshot-service/pb/service.pb.gw.go b/snapshot-service/pb/service.pb.gw.go index 6b1ebd723..a1cfec426 100644 --- a/snapshot-service/pb/service.pb.gw.go +++ b/snapshot-service/pb/service.pb.gw.go @@ -35,11 +35,7 @@ func request_SnapshotService_CreateCondition_0(ctx context.Context, marshaler ru var protoReq Condition var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -52,11 +48,7 @@ func local_request_SnapshotService_CreateCondition_0(ctx context.Context, marsha var protoReq Condition var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -133,11 +125,7 @@ func request_SnapshotService_UpdateCondition_0(ctx context.Context, marshaler ru var protoReq Condition var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -167,11 +155,7 @@ func local_request_SnapshotService_UpdateCondition_0(ctx context.Context, marsha var protoReq Condition var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -201,11 +185,7 @@ func request_SnapshotService_CreateConfiguration_0(ctx context.Context, marshale var protoReq Configuration var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -218,11 +198,7 @@ func local_request_SnapshotService_CreateConfiguration_0(ctx context.Context, ma var protoReq Configuration var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -299,11 +275,7 @@ func request_SnapshotService_UpdateConfiguration_0(ctx context.Context, marshale var protoReq Configuration var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -333,11 +305,7 @@ func local_request_SnapshotService_UpdateConfiguration_0(ctx context.Context, ma var protoReq Configuration var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -367,11 +335,7 @@ func request_SnapshotService_InvokeConfiguration_0(ctx context.Context, marshale var protoReq InvokeConfigurationRequest var metadata runtime.ServerMetadata - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -382,14 +346,14 @@ func request_SnapshotService_InvokeConfiguration_0(ctx context.Context, marshale _ = err ) - val, ok = pathParams["id"] + val, ok = pathParams["configuration_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "configuration_id") } - protoReq.Id, err = runtime.String(val) + protoReq.ConfigurationId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "configuration_id", err) } stream, err := client.InvokeConfiguration(ctx, &protoReq) @@ -410,7 +374,7 @@ var ( ) func request_SnapshotService_GetAppliedConfigurations_0(ctx context.Context, marshaler runtime.Marshaler, client SnapshotServiceClient, req *http.Request, pathParams map[string]string) (SnapshotService_GetAppliedConfigurationsClient, runtime.ServerMetadata, error) { - var protoReq GetAppliedConfigurationsRequest + var protoReq GetAppliedDeviceConfigurationsRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -438,7 +402,7 @@ var ( ) func request_SnapshotService_DeleteAppliedConfigurations_0(ctx context.Context, marshaler runtime.Marshaler, client SnapshotServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq DeleteAppliedConfigurationsRequest + var protoReq DeleteAppliedDeviceConfigurationsRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -454,7 +418,7 @@ func request_SnapshotService_DeleteAppliedConfigurations_0(ctx context.Context, } func local_request_SnapshotService_DeleteAppliedConfigurations_0(ctx context.Context, marshaler runtime.Marshaler, server SnapshotServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq DeleteAppliedConfigurationsRequest + var protoReq DeleteAppliedDeviceConfigurationsRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -684,21 +648,21 @@ func RegisterSnapshotServiceHandlerServer(ctx context.Context, mux *runtime.Serv // RegisterSnapshotServiceHandlerFromEndpoint is same as RegisterSnapshotServiceHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterSnapshotServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.DialContext(ctx, endpoint, opts...) + conn, err := grpc.NewClient(endpoint, opts...) if err != nil { return err } defer func() { if err != nil { if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } return } go func() { <-ctx.Done() if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } }() }() @@ -901,7 +865,7 @@ func RegisterSnapshotServiceHandlerClient(ctx context.Context, mux *runtime.Serv inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/snapshotservice.pb.SnapshotService/InvokeConfiguration", runtime.WithHTTPPathPattern("/api/v1/configurations/{id}")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/snapshotservice.pb.SnapshotService/InvokeConfiguration", runtime.WithHTTPPathPattern("/api/v1/configurations/{configuration_id}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -981,7 +945,7 @@ var ( pattern_SnapshotService_UpdateConfiguration_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "configurations", "id"}, "")) - pattern_SnapshotService_InvokeConfiguration_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "configurations", "id"}, "")) + pattern_SnapshotService_InvokeConfiguration_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "configurations", "configuration_id"}, "")) pattern_SnapshotService_GetAppliedConfigurations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "configurations", "applied"}, "")) diff --git a/snapshot-service/pb/service.proto b/snapshot-service/pb/service.proto index b56be34f6..f8261704b 100644 --- a/snapshot-service/pb/service.proto +++ b/snapshot-service/pb/service.proto @@ -62,8 +62,8 @@ message Condition { // driven by resource change event string owner = 11; } -message GetConditionsRequest { repeated IdFilter id_filter = 1; } -message DeleteConditionsRequest { repeated IdFilter id_filter = 1; } +message GetConditionsRequest { repeated IDFilter id_filter = 1; } +message DeleteConditionsRequest { repeated IDFilter id_filter = 1; } message DeleteConditionsResponse { int64 count = 1; } message Configuration { @@ -80,7 +80,7 @@ message Configuration { } message GetConfigurationsRequest { repeated IDFilter id_filter = 1; } -message DeleteConfigurationsRequest { repeated IdFilter id_filter = 1; } +message DeleteConfigurationsRequest { repeated IDFilter id_filter = 1; } message DeleteConfigurationsResponse { int64 count = 1; } message AppliedDeviceConfiguration { //TODO naming @@ -90,7 +90,7 @@ message AppliedDeviceConfiguration { //TODO naming enum Status { QUEUED = 0; PENDING = 1; - DONE = 2; If done look to resource_updated even update resource failed for resource aggregate. + DONE = 2; // If done look to resource_updated even update resource failed for resource aggregate. TIMEOUT = 3; }; Status status = 3; @@ -125,8 +125,8 @@ message GetAppliedDeviceConfigurationsRequest { //TODO Naming repeated IDFilter condition_id_filter = 4; } -message DeleteAppliedConfigurationsRequest { repeated string id_filter = 1; } -message DeleteAppliedConfigurationsResponse { int64 count = 1; } +message DeleteAppliedDeviceConfigurationsRequest { repeated string id_filter = 1; } +message DeleteAppliedDeviceConfigurationsResponse { int64 count = 1; } service SnapshotService { rpc CreateCondition(Condition) returns (Condition) { @@ -206,9 +206,9 @@ service SnapshotService { } // streaming process of update configuration to invoker - rpc InvokeConfiguration(InvokeConfigurationRequest) returns (stream AppliedConfiguration) { + rpc InvokeConfiguration(InvokeConfigurationRequest) returns (stream AppliedDeviceConfiguration) { option (google.api.http) = { - post: "/api/v1/configurations/{id}"; + post: "/api/v1/configurations/{configuration_id}"; body: "*"; }; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { @@ -217,7 +217,7 @@ service SnapshotService { } - rpc GetAppliedConfigurations(GetAppliedConfigurationsRequest) returns (stream AppliedConfiguration) { + rpc GetAppliedConfigurations(GetAppliedDeviceConfigurationsRequest) returns (stream AppliedDeviceConfiguration) { option (google.api.http) = { get: "/api/v1/configurations/applied"; }; @@ -226,7 +226,7 @@ service SnapshotService { }; } - rpc DeleteAppliedConfigurations(DeleteAppliedConfigurationsRequest) returns (DeleteAppliedConfigurationsResponse) { + rpc DeleteAppliedConfigurations(DeleteAppliedDeviceConfigurationsRequest) returns (DeleteAppliedDeviceConfigurationsResponse) { option (google.api.http) = { delete: "/api/v1/configurations/applied"; }; diff --git a/snapshot-service/pb/service.swagger.json b/snapshot-service/pb/service.swagger.json index d8dd64324..47265c7c8 100644 --- a/snapshot-service/pb/service.swagger.json +++ b/snapshot-service/pb/service.swagger.json @@ -141,43 +141,7 @@ "in": "body", "required": true, "schema": { - "type": "object", - "properties": { - "version": { - "type": "string", - "format": "uint64" - }, - "name": { - "type": "string" - }, - "enabled": { - "type": "boolean" - }, - "deviceIdFilter": { - "type": "array", - "items": { - "type": "string" - } - }, - "resourceTypeFilter": { - "type": "array", - "items": { - "type": "string" - } - }, - "resourceHrefFilter": { - "type": "array", - "items": { - "type": "string" - } - }, - "yqExpression": { - "type": "string" - }, - "invokeConfiguration": { - "$ref": "#/definitions/ConditionInvokeConfiguration" - } - } + "$ref": "#/definitions/SnapshotServiceUpdateConditionBody" } } ], @@ -277,13 +241,13 @@ "type": "object", "properties": { "result": { - "$ref": "#/definitions/pbAppliedConfiguration" + "$ref": "#/definitions/pbAppliedDeviceConfiguration" }, "error": { "$ref": "#/definitions/googlerpcStatus" } }, - "title": "Stream result of pbAppliedConfiguration" + "title": "Stream result of pbAppliedDeviceConfiguration" } }, "default": { @@ -313,16 +277,6 @@ "type": "string" }, "collectionFormat": "multi" - }, - { - "name": "conditionIdFilter", - "in": "query", - "required": false, - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi" } ], "tags": [ @@ -335,7 +289,7 @@ "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/pbDeleteAppliedConfigurationsResponse" + "$ref": "#/definitions/pbDeleteAppliedDeviceConfigurationsResponse" } }, "default": { @@ -362,7 +316,7 @@ ] } }, - "/api/v1/configurations/{id}": { + "/api/v1/configurations/{configurationId}": { "post": { "summary": "streaming process of update configuration to invoker", "operationId": "SnapshotService_InvokeConfiguration", @@ -373,13 +327,13 @@ "type": "object", "properties": { "result": { - "$ref": "#/definitions/pbAppliedConfiguration" + "$ref": "#/definitions/pbAppliedDeviceConfiguration" }, "error": { "$ref": "#/definitions/googlerpcStatus" } }, - "title": "Stream result of pbAppliedConfiguration" + "title": "Stream result of pbAppliedDeviceConfiguration" } }, "default": { @@ -391,7 +345,8 @@ }, "parameters": [ { - "name": "id", + "name": "configurationId", + "description": "applies latest configuration", "in": "path", "required": true, "type": "string" @@ -401,31 +356,16 @@ "in": "body", "required": true, "schema": { - "type": "object", - "properties": { - "deviceIdFilter": { - "type": "array", - "items": { - "type": "string" - }, - "title": "at least one must be set" - }, - "force": { - "type": "boolean", - "title": "force update even if the configuration has already been applied to device" - }, - "keepUpdatingOnFailure": { - "type": "boolean", - "title": "if any update resource fails continue with next resource" - } - } + "$ref": "#/definitions/SnapshotServiceInvokeConfigurationBody" } } ], "tags": [ "Configurations" ] - }, + } + }, + "/api/v1/configurations/{id}": { "put": { "operationId": "SnapshotService_UpdateConfiguration", "responses": { @@ -454,23 +394,7 @@ "in": "body", "required": true, "schema": { - "type": "object", - "properties": { - "version": { - "type": "string", - "format": "uint64" - }, - "name": { - "type": "string" - }, - "resources": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/pbConfigurationResource" - } - } - } + "$ref": "#/definitions/SnapshotServiceUpdateConfigurationBody" } } ], @@ -481,7 +405,7 @@ } }, "definitions": { - "AppliedConfigurationRelationTo": { + "AppliedDeviceConfigurationRelationTo": { "type": "object", "properties": { "id": { @@ -491,33 +415,102 @@ "type": "string", "format": "uint64" } - } + }, + "title": "TODO naming" }, - "AppliedConfigurationResourceStatus": { + "AppliedDeviceConfigurationResourceStatus": { "type": "string", "enum": [ "QUEUED", - "INPROGRESS", - "WAITING_FOR_REOURCE", + "PENDING", "DONE", - "TIMEOUT", - "FAIL" + "TIMEOUT" ], - "default": "QUEUED" + "default": "QUEUED", + "description": " - DONE: If done look to resource_updated even update resource failed for resource aggregate." }, - "ConditionInvokeConfiguration": { + "SnapshotServiceInvokeConfigurationBody": { "type": "object", "properties": { - "id": { + "deviceId": { + "type": "string" + }, + "force": { + "type": "boolean", + "title": "force update even if the configuration has already been applied to device" + }, + "correlationId": { + "type": "string", + "title": "propagated down to the resource update command" + } + } + }, + "SnapshotServiceUpdateConditionBody": { + "type": "object", + "properties": { + "version": { "type": "string", - "title": "latest version of cfg" + "format": "uint64" + }, + "name": { + "type": "string" }, - "keepUpdatingOnFailure": { + "enabled": { "type": "boolean" }, + "configurationId": { + "type": "string" + }, + "deviceIdFilter": { + "type": "array", + "items": { + "type": "string" + } + }, + "resourceTypeFilter": { + "type": "array", + "items": { + "type": "string" + } + }, + "resourceHrefFilter": { + "type": "array", + "items": { + "type": "string" + } + }, + "jqExpressionFilter": { + "type": "string" + }, "apiAccessToken": { "type": "string", "title": "token used to update resources in the configuration" + }, + "owner": { + "type": "string" + } + }, + "title": "driven by resource change event" + }, + "SnapshotServiceUpdateConfigurationBody": { + "type": "object", + "properties": { + "version": { + "type": "string", + "format": "uint64" + }, + "name": { + "type": "string" + }, + "resources": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/pbConfigurationResource" + } + }, + "owner": { + "type": "string" } } }, @@ -540,7 +533,7 @@ } } }, - "pbAppliedConfiguration": { + "pbAppliedDeviceConfiguration": { "type": "object", "properties": { "id": { @@ -550,46 +543,42 @@ "type": "string" }, "configurationId": { - "$ref": "#/definitions/AppliedConfigurationRelationTo" + "$ref": "#/definitions/AppliedDeviceConfigurationRelationTo" }, - "onDemaned": { + "onDemand": { "type": "boolean" }, "conditionId": { - "$ref": "#/definitions/AppliedConfigurationRelationTo" + "$ref": "#/definitions/AppliedDeviceConfigurationRelationTo", + "title": "TODO Naming" }, "resources": { "type": "array", "items": { "type": "object", - "$ref": "#/definitions/pbAppliedConfigurationResource" - } + "$ref": "#/definitions/pbAppliedDeviceConfigurationResource" + }, + "title": "TODO naming" + }, + "owner": { + "type": "string" } - } + }, + "title": "TODO naming" }, - "pbAppliedConfigurationResource": { + "pbAppliedDeviceConfigurationResource": { "type": "object", "properties": { "resourceId": { - "$ref": "#/definitions/pbResourceId" - }, - "configurationResourcesIdx": { - "type": "integer", - "format": "int64", - "description": "index of resource in configuration resources array. For resource types it could be mutliple resources." + "$ref": "#/definitions/pbResourceId", + "title": "TODO Jozo href only?" }, - "status": { - "$ref": "#/definitions/AppliedConfigurationResourceStatus" - }, - "timestampStart": { + "correlationId": { "type": "string", - "format": "int64", - "title": "when the rule association was applied" + "description": "Reused from invoke command or generated. Can be used to retrieve corresponding pending command." }, - "validUntil": { - "type": "string", - "format": "int64", - "title": "how long the command is valid" + "status": { + "$ref": "#/definitions/AppliedDeviceConfigurationResourceStatus" }, "resourceUpdated": { "$ref": "#/definitions/pbResourceUpdated" @@ -626,6 +615,9 @@ "enabled": { "type": "boolean" }, + "configurationId": { + "type": "string" + }, "deviceIdFilter": { "type": "array", "items": { @@ -644,13 +636,18 @@ "type": "string" } }, - "yqExpression": { + "jqExpressionFilter": { "type": "string" }, - "invokeConfiguration": { - "$ref": "#/definitions/ConditionInvokeConfiguration" + "apiAccessToken": { + "type": "string", + "title": "token used to update resources in the configuration" + }, + "owner": { + "type": "string" } - } + }, + "title": "driven by resource change event" }, "pbConfiguration": { "type": "object", @@ -671,6 +668,9 @@ "type": "object", "$ref": "#/definitions/pbConfigurationResource" } + }, + "owner": { + "type": "string" } } }, @@ -680,16 +680,13 @@ "href": { "type": "string" }, - "resourceTypes": { - "$ref": "#/definitions/pbResourceTypes" - }, "content": { "$ref": "#/definitions/pbContent" }, "timeToLive": { "type": "string", "format": "int64", - "title": "optional update command time to live" + "title": "optional update command time to live, 0 is infinite" } } }, @@ -710,7 +707,7 @@ } } }, - "pbDeleteAppliedConfigurationsResponse": { + "pbDeleteAppliedDeviceConfigurationsResponse": { "type": "object", "properties": { "count": { @@ -762,7 +759,7 @@ } } }, - "pbIdFilter": { + "pbIDFilter": { "type": "object", "properties": { "id": { @@ -775,10 +772,11 @@ "all": { "type": "boolean" }, - "max": { + "latest": { "type": "boolean" } - } + }, + "title": "/configuration/123?version=latest :) Jozko spravi :)" }, "pbResourceId": { "type": "object", @@ -791,23 +789,6 @@ } } }, - "pbResourceTypes": { - "type": "object", - "properties": { - "types": { - "type": "array", - "items": { - "type": "string" - }, - "title": "all types must match resource" - }, - "min": { - "type": "integer", - "format": "int64", - "title": "minimal number of resources that will be updated" - } - } - }, "pbResourceUpdated": { "type": "object", "properties": { @@ -826,6 +807,12 @@ "eventMetadata": { "$ref": "#/definitions/pbEventMetadata" }, + "resourceTypes": { + "type": "array", + "items": { + "type": "string" + } + }, "openTelemetryCarrier": { "type": "object", "additionalProperties": { diff --git a/snapshot-service/pb/service_grpc.pb.go b/snapshot-service/pb/service_grpc.pb.go index c1c6f2dbe..d23d4e0af 100644 --- a/snapshot-service/pb/service_grpc.pb.go +++ b/snapshot-service/pb/service_grpc.pb.go @@ -1,7 +1,15 @@ +// TODO overit ze pending command sa nezmaze na neexistujucom resource ak sa device pripoji a nepublishne hned resource +// Overit correlation id - ak sa pouziva rovnake napriec viacerymi resourcami + +// scenare +// - Uzivatel vie vytvorit config, automaticka (backend) inkrementacia verzie +// - Uzivatel updatne config, verzia sa inkrementuje, Modal -> chces aplikovat na vsetky uz provisionnute devici? Informovat uzivatela, ze niektore devici mozu byt offline a command moze vyexpirovat. +// - Uzivatel updatne config, verzia sa inkrementuje, informujeme uzivatela ze vsetky pending commandy z predoslej verzie budu cancelnute ako aj dalsie sekvencne updaty resourcov pre predoslu verziu + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc v5.26.1 // source: snapshot-service/pb/service.proto package pb @@ -46,8 +54,8 @@ type SnapshotServiceClient interface { UpdateConfiguration(ctx context.Context, in *Configuration, opts ...grpc.CallOption) (*Configuration, error) // streaming process of update configuration to invoker InvokeConfiguration(ctx context.Context, in *InvokeConfigurationRequest, opts ...grpc.CallOption) (SnapshotService_InvokeConfigurationClient, error) - GetAppliedConfigurations(ctx context.Context, in *GetAppliedConfigurationsRequest, opts ...grpc.CallOption) (SnapshotService_GetAppliedConfigurationsClient, error) - DeleteAppliedConfigurations(ctx context.Context, in *DeleteAppliedConfigurationsRequest, opts ...grpc.CallOption) (*DeleteAppliedConfigurationsResponse, error) + GetAppliedConfigurations(ctx context.Context, in *GetAppliedDeviceConfigurationsRequest, opts ...grpc.CallOption) (SnapshotService_GetAppliedConfigurationsClient, error) + DeleteAppliedConfigurations(ctx context.Context, in *DeleteAppliedDeviceConfigurationsRequest, opts ...grpc.CallOption) (*DeleteAppliedDeviceConfigurationsResponse, error) } type snapshotServiceClient struct { @@ -192,7 +200,7 @@ func (c *snapshotServiceClient) InvokeConfiguration(ctx context.Context, in *Inv } type SnapshotService_InvokeConfigurationClient interface { - Recv() (*AppliedConfiguration, error) + Recv() (*AppliedDeviceConfiguration, error) grpc.ClientStream } @@ -200,15 +208,15 @@ type snapshotServiceInvokeConfigurationClient struct { grpc.ClientStream } -func (x *snapshotServiceInvokeConfigurationClient) Recv() (*AppliedConfiguration, error) { - m := new(AppliedConfiguration) +func (x *snapshotServiceInvokeConfigurationClient) Recv() (*AppliedDeviceConfiguration, error) { + m := new(AppliedDeviceConfiguration) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } -func (c *snapshotServiceClient) GetAppliedConfigurations(ctx context.Context, in *GetAppliedConfigurationsRequest, opts ...grpc.CallOption) (SnapshotService_GetAppliedConfigurationsClient, error) { +func (c *snapshotServiceClient) GetAppliedConfigurations(ctx context.Context, in *GetAppliedDeviceConfigurationsRequest, opts ...grpc.CallOption) (SnapshotService_GetAppliedConfigurationsClient, error) { stream, err := c.cc.NewStream(ctx, &SnapshotService_ServiceDesc.Streams[3], SnapshotService_GetAppliedConfigurations_FullMethodName, opts...) if err != nil { return nil, err @@ -224,7 +232,7 @@ func (c *snapshotServiceClient) GetAppliedConfigurations(ctx context.Context, in } type SnapshotService_GetAppliedConfigurationsClient interface { - Recv() (*AppliedConfiguration, error) + Recv() (*AppliedDeviceConfiguration, error) grpc.ClientStream } @@ -232,16 +240,16 @@ type snapshotServiceGetAppliedConfigurationsClient struct { grpc.ClientStream } -func (x *snapshotServiceGetAppliedConfigurationsClient) Recv() (*AppliedConfiguration, error) { - m := new(AppliedConfiguration) +func (x *snapshotServiceGetAppliedConfigurationsClient) Recv() (*AppliedDeviceConfiguration, error) { + m := new(AppliedDeviceConfiguration) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } -func (c *snapshotServiceClient) DeleteAppliedConfigurations(ctx context.Context, in *DeleteAppliedConfigurationsRequest, opts ...grpc.CallOption) (*DeleteAppliedConfigurationsResponse, error) { - out := new(DeleteAppliedConfigurationsResponse) +func (c *snapshotServiceClient) DeleteAppliedConfigurations(ctx context.Context, in *DeleteAppliedDeviceConfigurationsRequest, opts ...grpc.CallOption) (*DeleteAppliedDeviceConfigurationsResponse, error) { + out := new(DeleteAppliedDeviceConfigurationsResponse) err := c.cc.Invoke(ctx, SnapshotService_DeleteAppliedConfigurations_FullMethodName, in, out, opts...) if err != nil { return nil, err @@ -263,8 +271,8 @@ type SnapshotServiceServer interface { UpdateConfiguration(context.Context, *Configuration) (*Configuration, error) // streaming process of update configuration to invoker InvokeConfiguration(*InvokeConfigurationRequest, SnapshotService_InvokeConfigurationServer) error - GetAppliedConfigurations(*GetAppliedConfigurationsRequest, SnapshotService_GetAppliedConfigurationsServer) error - DeleteAppliedConfigurations(context.Context, *DeleteAppliedConfigurationsRequest) (*DeleteAppliedConfigurationsResponse, error) + GetAppliedConfigurations(*GetAppliedDeviceConfigurationsRequest, SnapshotService_GetAppliedConfigurationsServer) error + DeleteAppliedConfigurations(context.Context, *DeleteAppliedDeviceConfigurationsRequest) (*DeleteAppliedDeviceConfigurationsResponse, error) mustEmbedUnimplementedSnapshotServiceServer() } @@ -299,10 +307,10 @@ func (UnimplementedSnapshotServiceServer) UpdateConfiguration(context.Context, * func (UnimplementedSnapshotServiceServer) InvokeConfiguration(*InvokeConfigurationRequest, SnapshotService_InvokeConfigurationServer) error { return status.Errorf(codes.Unimplemented, "method InvokeConfiguration not implemented") } -func (UnimplementedSnapshotServiceServer) GetAppliedConfigurations(*GetAppliedConfigurationsRequest, SnapshotService_GetAppliedConfigurationsServer) error { +func (UnimplementedSnapshotServiceServer) GetAppliedConfigurations(*GetAppliedDeviceConfigurationsRequest, SnapshotService_GetAppliedConfigurationsServer) error { return status.Errorf(codes.Unimplemented, "method GetAppliedConfigurations not implemented") } -func (UnimplementedSnapshotServiceServer) DeleteAppliedConfigurations(context.Context, *DeleteAppliedConfigurationsRequest) (*DeleteAppliedConfigurationsResponse, error) { +func (UnimplementedSnapshotServiceServer) DeleteAppliedConfigurations(context.Context, *DeleteAppliedDeviceConfigurationsRequest) (*DeleteAppliedDeviceConfigurationsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteAppliedConfigurations not implemented") } func (UnimplementedSnapshotServiceServer) mustEmbedUnimplementedSnapshotServiceServer() {} @@ -477,7 +485,7 @@ func _SnapshotService_InvokeConfiguration_Handler(srv interface{}, stream grpc.S } type SnapshotService_InvokeConfigurationServer interface { - Send(*AppliedConfiguration) error + Send(*AppliedDeviceConfiguration) error grpc.ServerStream } @@ -485,12 +493,12 @@ type snapshotServiceInvokeConfigurationServer struct { grpc.ServerStream } -func (x *snapshotServiceInvokeConfigurationServer) Send(m *AppliedConfiguration) error { +func (x *snapshotServiceInvokeConfigurationServer) Send(m *AppliedDeviceConfiguration) error { return x.ServerStream.SendMsg(m) } func _SnapshotService_GetAppliedConfigurations_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(GetAppliedConfigurationsRequest) + m := new(GetAppliedDeviceConfigurationsRequest) if err := stream.RecvMsg(m); err != nil { return err } @@ -498,7 +506,7 @@ func _SnapshotService_GetAppliedConfigurations_Handler(srv interface{}, stream g } type SnapshotService_GetAppliedConfigurationsServer interface { - Send(*AppliedConfiguration) error + Send(*AppliedDeviceConfiguration) error grpc.ServerStream } @@ -506,12 +514,12 @@ type snapshotServiceGetAppliedConfigurationsServer struct { grpc.ServerStream } -func (x *snapshotServiceGetAppliedConfigurationsServer) Send(m *AppliedConfiguration) error { +func (x *snapshotServiceGetAppliedConfigurationsServer) Send(m *AppliedDeviceConfiguration) error { return x.ServerStream.SendMsg(m) } func _SnapshotService_DeleteAppliedConfigurations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(DeleteAppliedConfigurationsRequest) + in := new(DeleteAppliedDeviceConfigurationsRequest) if err := dec(in); err != nil { return nil, err } @@ -523,7 +531,7 @@ func _SnapshotService_DeleteAppliedConfigurations_Handler(srv interface{}, ctx c FullMethod: SnapshotService_DeleteAppliedConfigurations_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SnapshotServiceServer).DeleteAppliedConfigurations(ctx, req.(*DeleteAppliedConfigurationsRequest)) + return srv.(SnapshotServiceServer).DeleteAppliedConfigurations(ctx, req.(*DeleteAppliedDeviceConfigurationsRequest)) } return interceptor(ctx, in, info, handler) } diff --git a/snapshot-service/service/config.go b/snapshot-service/service/config.go index dd2d211be..67e6998d4 100644 --- a/snapshot-service/service/config.go +++ b/snapshot-service/service/config.go @@ -5,7 +5,7 @@ import ( "net" "time" - gocron "github.com/go-co-op/gocron" + "github.com/go-co-op/gocron/v2" "github.com/google/uuid" "github.com/plgd-dev/hub/v2/pkg/config" "github.com/plgd-dev/hub/v2/pkg/log" @@ -80,20 +80,22 @@ func (c *StorageConfig) Validate() error { if c.CleanUpRecords == "" { return nil } - s := gocron.NewScheduler(time.Local) - if c.ExtendCronParserBySeconds { - s = s.CronWithSeconds(c.CleanUpRecords) - } else { - s = s.Cron(c.CleanUpRecords) + s, err := gocron.NewScheduler(gocron.WithLocation(time.Local)) //nolint:gosmopolitan + if err != nil { + return fmt.Errorf("cannot create cron job: %w", err) } - _, err := s.Do(func() { - // do nothing - }) + defer func() { + if errS := s.Shutdown(); errS != nil { + log.Errorf("failed to shutdown cron job: %w", errS) + } + }() + _, err = s.NewJob(gocron.CronJob(c.CleanUpRecords, c.ExtendCronParserBySeconds), + gocron.NewTask(func() { + // do nothing + })) if err != nil { return fmt.Errorf("cleanUpRecords('%v') - %w", c.CleanUpRecords, err) } - s.Clear() - s.Stop() return nil } diff --git a/snapshot-service/service/service.go b/snapshot-service/service/service.go index 78ad2fdfa..82e87789f 100644 --- a/snapshot-service/service/service.go +++ b/snapshot-service/service/service.go @@ -5,7 +5,7 @@ import ( "fmt" "time" - gocron "github.com/go-co-op/gocron" + "github.com/go-co-op/gocron/v2" "github.com/plgd-dev/hub/v2/pkg/config/database" "github.com/plgd-dev/hub/v2/pkg/fn" "github.com/plgd-dev/hub/v2/pkg/fsnotify" @@ -51,35 +51,36 @@ func newStore(ctx context.Context, config StorageConfig, fileWatcher *fsnotify.W return nil, nil, err } fl.AddFunc(func() { - if err := db.Close(ctx); err != nil { - log.Errorf("failed to close mongodb store: %w", err) + if errC := db.Close(ctx); errC != nil { + log.Errorf("failed to close mongodb store: %w", errC) } }) if config.CleanUpRecords == "" { return db, fl.ToFunction(), nil } - s := gocron.NewScheduler(time.Local) - if config.ExtendCronParserBySeconds { - s = s.CronWithSeconds(config.CleanUpRecords) - } else { - s = s.Cron(config.CleanUpRecords) + s, err := gocron.NewScheduler(gocron.WithLocation(time.Local)) //nolint:gosmopolitan + if err != nil { + fl.Execute() + return nil, nil, fmt.Errorf("cannot create cron job: %w", err) } - _, err = s.Do(func() { + _, err = s.NewJob(gocron.CronJob(config.CleanUpRecords, config.ExtendCronParserBySeconds), gocron.NewTask(func() { /* _, errDel := db.DeleteNonDeviceExpiredRecords(ctx, time.Now()) if errDel != nil && !errors.Is(errDel, store.ErrNotSupported) { log.Errorf("failed to delete expired signing records: %w", errDel) } */ - }) + })) if err != nil { fl.Execute() return nil, nil, fmt.Errorf("cannot create cron job: %w", err) } - fl.AddFunc(s.Clear) - fl.AddFunc(s.Stop) - s.StartAsync() - + fl.AddFunc(func() { + if errS := s.Shutdown(); errS != nil { + log.Errorf("failed to shutdown cron job: %w", errS) + } + }) + s.Start() return db, fl.ToFunction(), nil } diff --git a/snapshot-service/store/mongodb/store.go b/snapshot-service/store/mongodb/store.go index e124bee5d..c4265d6b9 100644 --- a/snapshot-service/store/mongodb/store.go +++ b/snapshot-service/store/mongodb/store.go @@ -28,9 +28,7 @@ func New(ctx context.Context, cfg *Config, fileWatcher *fsnotify.Watcher, logger return nil, err } s := Store{Store: m} - s.SetOnClear(func(c context.Context) error { - return s.clearDatabases(ctx) - }) + s.SetOnClear(s.clearDatabases) s.AddCloseFunc(certManager.Close) return &s, nil } diff --git a/test/bridge-device/bridge-device.jsonld b/test/bridge-device/bridge-device.jsonld new file mode 100644 index 000000000..4b72a02b6 --- /dev/null +++ b/test/bridge-device/bridge-device.jsonld @@ -0,0 +1,8 @@ +{ + "@context": "https://www.w3.org/2019/wot/td/v1", + "@type": [ + "Thing" + ], + "id": "urn:uuid:bridge-test", + "properties": {} +} \ No newline at end of file diff --git a/test/bridge-device/config.yaml b/test/bridge-device/config.yaml new file mode 100644 index 000000000..5be18ae10 --- /dev/null +++ b/test/bridge-device/config.yaml @@ -0,0 +1,19 @@ +apis: + coap: + id: 8f596b43-29c0-4147-8b40-e99268ab30f7 + name: "bridge-test" + externalAddresses: + - "127.0.0.1:15683" + - "[::1]:15683" + maxMessageSize: 2097152 +log: + level: "info" +cloud: + enabled: true +credential: + enabled: true +thingDescription: + enabled: true + file: "bridge-device.jsonld" +numGeneratedBridgedDevices: 3 +numResourcesPerDevice: 3 diff --git a/test/cbor.go b/test/cbor.go index 8c23ee146..0e0d48571 100644 --- a/test/cbor.go +++ b/test/cbor.go @@ -5,13 +5,13 @@ import ( "github.com/fxamacker/cbor/v2" pkgCbor "github.com/plgd-dev/kit/v2/codec/cbor" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" ) func DecodeCbor(t *testing.T, data []byte) interface{} { var v interface{} err := pkgCbor.Decode(data, &v) - require.NoError(t, err) + assert.NoError(t, err) return v } @@ -25,6 +25,6 @@ func EncodeToSortedCbor(v interface{}) ([]byte, error) { func EncodeToCbor(t *testing.T, v interface{}) []byte { d, err := EncodeToSortedCbor(v) - require.NoError(t, err) + assert.NoError(t, err) return d } diff --git a/test/cloud-server/Dockerfile b/test/cloud-server/Dockerfile index fa37f1da6..a4542f439 100644 --- a/test/cloud-server/Dockerfile +++ b/test/cloud-server/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM golang:1.20.13-alpine AS build +FROM golang:1.22.3-alpine AS build ARG VERSION ARG COMMIT_DATE ARG SHORT_COMMIT @@ -10,7 +10,8 @@ WORKDIR $GOPATH/src/github.com/plgd-dev/hub COPY go.mod go.sum ./ RUN go mod download COPY . . -RUN ( cd /usr/local/go && patch -p1 < $GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch ) +WORKDIR /usr/local/go +RUN ( patch -p1 < "$GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch" ) ARG root_directory=$GOPATH/src/github.com/plgd-dev/hub #cert-tool @@ -18,6 +19,12 @@ ARG tool=cert-tool WORKDIR $root_directory/tools/$tool RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/cert-tool +#coap-gateway +#the "device_integration" tag should ensure that only integration tests with a device simulator are compiled +ARG service=coap-gateway +WORKDIR $root_directory/$service/service +RUN go test -p 1 -c -tags=device_integration -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/coap-gateway.test + #grpc-gateway ARG service=grpc-gateway WORKDIR $root_directory/$service/service @@ -49,17 +56,20 @@ RUN unzip ./nats.zip -d ./nats RUN cp ./nats/*/nats /go/bin/nats FROM ubuntu:22.04 AS service -RUN apt update # iproute2 -> ip utility in run.sh # netcat -> nc utility in run.sh # nginx -> nginx server in run.sh # openssl -> openssl utility in run.sh -RUN apt-get install -y --no-install-recommends ca-certificates gnupg iproute2 netcat nginx openssl wget +RUN apt update \ + && apt-get install -y --no-install-recommends ca-certificates gnupg iproute2 netcat nginx openssl wget \ + && apt-get clean RUN wget -qO - https://pgp.mongodb.com/server-6.0.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/mongodb-6.0.gpg RUN echo "deb [ arch=$(dpkg --print-architecture) ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-6.0.list -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends mongodb-org mongodb-org-server +RUN apt update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends mongodb-org mongodb-org-server \ + && apt-get clean COPY --from=build /go/bin/cert-tool /usr/local/bin/cert-tool +COPY --from=build /go/bin/coap-gateway.test /usr/local/bin/coap-gateway.test COPY --from=build /go/bin/grpc-gateway.test /usr/local/bin/grpc-gateway.test COPY --from=build /go/bin/test-iotivity-lite.test /usr/local/bin/test-iotivity-lite.test COPY --from=build /go/bin/nats-server /usr/local/bin/nats-server @@ -68,6 +78,8 @@ COPY test/cloud-server/run.sh /usr/local/bin/run.sh # global ENV FQDN="localhost" +ENV PREPARE_ENV="true" +ENV RUN="true" # global - certificates generated by cert-tool ENV CERT_TOOL_SIGN_ALG=ECDSA-SHA256 diff --git a/test/cloud-server/run.sh b/test/cloud-server/run.sh index ad49eb459..a11d74811 100755 --- a/test/cloud-server/run.sh +++ b/test/cloud-server/run.sh @@ -6,119 +6,91 @@ umask 0000 # Configure services export PATH="/usr/local/bin:$PATH" -export COAP_GATEWAY_CLOUD_ID="adebc667-1f2b-41e3-bf5c-6d6eabc68cc6" +if [ -z "${COAP_GATEWAY_CLOUD_ID}" ]; then + COAP_GATEWAY_CLOUD_ID="adebc667-1f2b-41e3-bf5c-6d6eabc68cc6" +fi -export CERTIFICATES_PATH="/data/certs" -export OAUTH_KEYS_PATH="/data/oauth/keys" -export OAUTH_SECRETS_PATH="/data/oauth/secrets" -export LOGS_PATH="/data/log" -export MONGO_PATH="/data/db" +CERTIFICATES_PATH="/data/certs" +LOGS_PATH="/data/log" +MONGO_PATH="/data/db" -export INTERNAL_CERT_DIR_PATH="$CERTIFICATES_PATH/internal" -export GRPC_INTERNAL_CERT_NAME="endpoint.crt" -export GRPC_INTERNAL_CERT_KEY_NAME="endpoint.key" +INTERNAL_CERT_DIR_PATH="$CERTIFICATES_PATH/internal" +GRPC_INTERNAL_CERT_NAME="endpoint.crt" +GRPC_INTERNAL_CERT_KEY_NAME="endpoint.key" -export EXTERNAL_CERT_DIR_PATH="$CERTIFICATES_PATH/external" -export COAP_GATEWAY_FILE_CERT_NAME="coap-gateway.crt" -export COAP_GATEWAY_FILE_CERT_KEY_NAME="coap-gateway.key" +EXTERNAL_CERT_DIR_PATH="$CERTIFICATES_PATH/external" +COAP_GATEWAY_FILE_CERT_NAME="coap-gateway.crt" +COAP_GATEWAY_FILE_CERT_KEY_NAME="coap-gateway.key" # ROOT CERTS -export CA_POOL_DIR="$CERTIFICATES_PATH" -export CA_POOL_NAME_PREFIX="root_ca" -export CA_POOL_CERT_PATH="$CA_POOL_DIR/$CA_POOL_NAME_PREFIX.crt" -export CA_POOL_CERT_KEY_PATH="$CA_POOL_DIR/$CA_POOL_NAME_PREFIX.key" +CA_POOL_DIR="$CERTIFICATES_PATH" +CA_POOL_NAME_PREFIX="root_ca" +CA_POOL_CERT_PATH="$CA_POOL_DIR/$CA_POOL_NAME_PREFIX.crt" +CA_POOL_CERT_KEY_PATH="$CA_POOL_DIR/$CA_POOL_NAME_PREFIX.key" # DIAL CERTS -export DIAL_FILE_CA_POOL="$CA_POOL_CERT_PATH" -export DIAL_FILE_CERT_DIR_PATH="$INTERNAL_CERT_DIR_PATH" -export DIAL_FILE_CERT_NAME="$GRPC_INTERNAL_CERT_NAME" -export DIAL_FILE_CERT_KEY_NAME="$GRPC_INTERNAL_CERT_KEY_NAME" - -#LISTEN CERTS -export LISTEN_FILE_CA_POOL="$CA_POOL_CERT_PATH" -export LISTEN_FILE_CERT_DIR_PATH="$INTERNAL_CERT_DIR_PATH" -export LISTEN_FILE_CERT_NAME="$GRPC_INTERNAL_CERT_NAME" -export LISTEN_FILE_CERT_KEY_NAME="$GRPC_INTERNAL_CERT_KEY_NAME" - -#SECRETS -export SECRETS_DIRECTORY=/data/secrets - -#OAUTH-SEVER KEYS -export OAUTH_ID_TOKEN_KEY_PATH=${OAUTH_KEYS_PATH}/id-token.pem -export OAUTH_ACCESS_TOKEN_KEY_PATH=${OAUTH_KEYS_PATH}/access-token.pem - -export OAUTH_DEVICE_SECRET_PATH=${OAUTH_SECRETS_PATH}/device.secret - -#ENDPOINTS -export MONGODB_HOST="localhost:$MONGO_PORT" -export MONGODB_URI="mongodb://$MONGODB_HOST" -export NATS_HOST="localhost:$NATS_PORT" -export NATS_URL="nats://${NATS_HOST}" - -# needed by grpc-gateway.test -export TEST_COAP_GW_CERT_FILE="${EXTERNAL_CERT_DIR_PATH}/${COAP_GATEWAY_FILE_CERT_NAME}" -export TEST_COAP_GW_KEY_FILE="${EXTERNAL_CERT_DIR_PATH}/${COAP_GATEWAY_FILE_CERT_KEY_NAME}" -export TEST_ROOT_CA_CERT="${CA_POOL_CERT_PATH}" -export TEST_ROOT_CA_KEY="${CA_POOL_CERT_KEY_PATH}" -export TEST_CLOUD_SID="${COAP_GATEWAY_CLOUD_ID}" -export TEST_OAUTH_SERVER_ID_TOKEN_PRIVATE_KEY="${OAUTH_ID_TOKEN_KEY_PATH}" -export TEST_OAUTH_SERVER_ACCESS_TOKEN_PRIVATE_KEY="${OAUTH_ACCESS_TOKEN_KEY_PATH}" -export TEST_COAP_GATEWAY_UDP_ENABLED="${COAP_GATEWAY_UDP_ENABLED}" - -mkdir -p ${OAUTH_SECRETS_PATH} -if [ -z "${OAUTH_CLIENT_SECRET}" ] -then - export OAUTH_CLIENT_SECRET="secret" -fi -echo -n ${OAUTH_CLIENT_SECRET} > ${OAUTH_DEVICE_SECRET_PATH} +DIAL_FILE_CERT_DIR_PATH="$INTERNAL_CERT_DIR_PATH" +DIAL_FILE_CERT_NAME="$GRPC_INTERNAL_CERT_NAME" +DIAL_FILE_CERT_KEY_NAME="$GRPC_INTERNAL_CERT_KEY_NAME" -mkdir -p $CA_POOL_DIR -mkdir -p $INTERNAL_CERT_DIR_PATH -mkdir -p $EXTERNAL_CERT_DIR_PATH -mkdir -p ${SECRETS_DIRECTORY} -ln -s ${SECRETS_DIRECTORY} /secrets - -export CA_POOL=$CA_POOL_CERT_PATH -export CERT_FILE=$DIAL_FILE_CERT_DIR_PATH/$DIAL_FILE_CERT_NAME -export KEY_FILE=$DIAL_FILE_CERT_DIR_PATH/$DIAL_FILE_CERT_KEY_NAME +# OAUTH-SEVER KEYS +OAUTH_KEYS_PATH="/data/oauth/keys" +OAUTH_ID_TOKEN_KEY_PATH=${OAUTH_KEYS_PATH}/id-token.pem +OAUTH_ACCESS_TOKEN_KEY_PATH=${OAUTH_KEYS_PATH}/access-token.pem CERT_TOOL_SIGN_ALG=${CERT_TOOL_SIGN_ALG:-ECDSA-SHA256} CERT_TOOL_ELLIPTIC_CURVE=${CERT_TOOL_ELLIPTIC_CURVE:-P256} -fqdnSAN="--cert.san.domain=$FQDN" -if ip route get $FQDN 2>/dev/null >/dev/null; then - fqdnSAN="--cert.san.ip=$FQDN" -fi -echo "generating CA cert" -cert-tool --cmd.generateRootCA --outCert=$CA_POOL_CERT_PATH --outKey=$CA_POOL_CERT_KEY_PATH --cert.subject.cn="Root CA" \ - --cert.signatureAlgorithm=${CERT_TOOL_SIGN_ALG} --cert.ellipticCurve=${CERT_TOOL_ELLIPTIC_CURVE} -echo "generating GRPC internal cert" -cert-tool --cmd.generateCertificate --outCert=$DIAL_FILE_CERT_DIR_PATH/$DIAL_FILE_CERT_NAME \ - --outKey=$DIAL_FILE_CERT_DIR_PATH/$DIAL_FILE_CERT_KEY_NAME --cert.subject.cn="localhost" --cert.san.domain="localhost" \ - --cert.san.ip="0.0.0.0" --cert.san.ip="127.0.0.1" $fqdnSAN --signerCert=$CA_POOL_CERT_PATH --signerKey=$CA_POOL_CERT_KEY_PATH \ - --cert.signatureAlgorithm=${CERT_TOOL_SIGN_ALG} --cert.ellipticCurve=${CERT_TOOL_ELLIPTIC_CURVE} -echo "generating COAP-GW cert" -cert-tool --cmd.generateIdentityCertificate=$COAP_GATEWAY_CLOUD_ID --outCert=$EXTERNAL_CERT_DIR_PATH/$COAP_GATEWAY_FILE_CERT_NAME \ - --outKey=$EXTERNAL_CERT_DIR_PATH/$COAP_GATEWAY_FILE_CERT_KEY_NAME --cert.san.domain=$COAP_GATEWAY_FQDN \ - --signerCert=$CA_POOL_CERT_PATH --signerKey=$CA_POOL_CERT_KEY_PATH --cert.signatureAlgorithm=${CERT_TOOL_SIGN_ALG} \ - --cert.ellipticCurve=${CERT_TOOL_ELLIPTIC_CURVE} -echo "generating NGINX cert" -cert-tool --cmd.generateCertificate --outCert=$EXTERNAL_CERT_DIR_PATH/$DIAL_FILE_CERT_NAME \ - --outKey=$EXTERNAL_CERT_DIR_PATH/$DIAL_FILE_CERT_KEY_NAME --cert.subject.cn="localhost" --cert.san.domain="localhost" \ - --cert.san.ip="0.0.0.0" --cert.san.ip="127.0.0.1" $fqdnSAN --signerCert=$CA_POOL_CERT_PATH --signerKey=$CA_POOL_CERT_KEY_PATH \ - --cert.signatureAlgorithm=${CERT_TOOL_SIGN_ALG} --cert.ellipticCurve=${CERT_TOOL_ELLIPTIC_CURVE} - -mkdir -p ${OAUTH_KEYS_PATH} -openssl genrsa -out ${OAUTH_ID_TOKEN_KEY_PATH} 4096 -openssl ecparam -name prime256v1 -genkey -noout -out ${OAUTH_ACCESS_TOKEN_KEY_PATH} - -mkdir -p $MONGO_PATH -mkdir -p $CERTIFICATES_PATH -mkdir -p $LOGS_PATH - -# nats -echo "starting nats-server" -cat > /data/nats.config < ${OAUTH_DEVICE_SECRET_PATH} + + mkdir -p $CERTIFICATES_PATH + mkdir -p $CA_POOL_DIR + mkdir -p $INTERNAL_CERT_DIR_PATH + mkdir -p $EXTERNAL_CERT_DIR_PATH + + fqdnSAN="--cert.san.domain=$FQDN" + if ip route get $FQDN 2>/dev/null >/dev/null; then + fqdnSAN="--cert.san.ip=$FQDN" + fi + echo "generating CA cert" + cert-tool --cmd.generateRootCA --outCert=$CA_POOL_CERT_PATH --outKey=$CA_POOL_CERT_KEY_PATH --cert.subject.cn="Root CA" \ + --cert.signatureAlgorithm=${CERT_TOOL_SIGN_ALG} --cert.ellipticCurve=${CERT_TOOL_ELLIPTIC_CURVE} + echo "generating GRPC internal cert" + cert-tool --cmd.generateCertificate --outCert=$DIAL_FILE_CERT_DIR_PATH/$DIAL_FILE_CERT_NAME \ + --outKey=$DIAL_FILE_CERT_DIR_PATH/$DIAL_FILE_CERT_KEY_NAME --cert.subject.cn="localhost" --cert.san.domain="localhost" \ + --cert.san.ip="0.0.0.0" --cert.san.ip="127.0.0.1" $fqdnSAN --signerCert=$CA_POOL_CERT_PATH --signerKey=$CA_POOL_CERT_KEY_PATH \ + --cert.signatureAlgorithm=${CERT_TOOL_SIGN_ALG} --cert.ellipticCurve=${CERT_TOOL_ELLIPTIC_CURVE} + echo "generating COAP-GW cert" + cert-tool --cmd.generateIdentityCertificate=$COAP_GATEWAY_CLOUD_ID --outCert=$EXTERNAL_CERT_DIR_PATH/$COAP_GATEWAY_FILE_CERT_NAME \ + --outKey=$EXTERNAL_CERT_DIR_PATH/$COAP_GATEWAY_FILE_CERT_KEY_NAME --cert.san.domain=$COAP_GATEWAY_FQDN \ + --signerCert=$CA_POOL_CERT_PATH --signerKey=$CA_POOL_CERT_KEY_PATH --cert.signatureAlgorithm=${CERT_TOOL_SIGN_ALG} \ + --cert.ellipticCurve=${CERT_TOOL_ELLIPTIC_CURVE} + echo "generating NGINX cert" + cert-tool --cmd.generateCertificate --outCert=$EXTERNAL_CERT_DIR_PATH/$DIAL_FILE_CERT_NAME \ + --outKey=$EXTERNAL_CERT_DIR_PATH/$DIAL_FILE_CERT_KEY_NAME --cert.subject.cn="localhost" --cert.san.domain="localhost" \ + --cert.san.ip="0.0.0.0" --cert.san.ip="127.0.0.1" $fqdnSAN --signerCert=$CA_POOL_CERT_PATH --signerKey=$CA_POOL_CERT_KEY_PATH \ + --cert.signatureAlgorithm=${CERT_TOOL_SIGN_ALG} --cert.ellipticCurve=${CERT_TOOL_ELLIPTIC_CURVE} + + mkdir -p ${OAUTH_KEYS_PATH} + openssl genrsa -out ${OAUTH_ID_TOKEN_KEY_PATH} 4096 + openssl ecparam -name prime256v1 -genkey -noout -out ${OAUTH_ACCESS_TOKEN_KEY_PATH} + + # nats + cat > /data/nats.config <$LOGS_PATH/nats-server.log 2>&1 & -status=$? -nats_server_pid=$! -if [ $status -ne 0 ]; then - echo "Failed to start nats-server: $status" - sync - cat $LOGS_PATH/nats-server.log - exit $status + # mongo + mkdir -p $MONGO_PATH + cat $DIAL_FILE_CERT_DIR_PATH/$DIAL_FILE_CERT_NAME > $DIAL_FILE_CERT_DIR_PATH/mongo.key + cat $DIAL_FILE_CERT_DIR_PATH/$DIAL_FILE_CERT_KEY_NAME >> $DIAL_FILE_CERT_DIR_PATH/mongo.key fi -# waiting for nats. Without wait, sometimes auth service didn't connect. -i=0 -while true; do - i=$((i+1)) - if nc -z localhost $NATS_PORT; then - break +if [ "${RUN}" == "true" ]; then + # nats + export NATS_HOST="localhost:$NATS_PORT" + export NATS_URL="nats://${NATS_HOST}" + + echo "starting nats-server" + nats-server -c /data/nats.config >$LOGS_PATH/nats-server.log 2>&1 & + status=$? + nats_server_pid=$! + if [ $status -ne 0 ]; then + echo "Failed to start nats-server: $status" + sync + cat $LOGS_PATH/nats-server.log + exit $status + fi + + # waiting for nats. Without wait, sometimes auth service didn't connect. + i=0 + while true; do + i=$((i+1)) + if nc -z localhost $NATS_PORT; then + break + fi + echo "Try to reconnect to nats(${NATS_HOST}) $i" + sleep 1 + done + + # mongo + export MONGODB_HOST="localhost:$MONGO_PORT" + export MONGODB_URI="mongodb://$MONGODB_HOST" + + echo "starting mongod" + mongod --setParameter maxNumActiveUserIndexBuilds=64 --port $MONGO_PORT --dbpath $MONGO_PATH \ + --sslMode requireSSL --sslCAFile $CA_POOL_CERT_PATH --sslPEMKeyFile $DIAL_FILE_CERT_DIR_PATH/mongo.key \ + >$LOGS_PATH/mongod.log 2>&1 & + status=$? + mongo_pid=$! + if [ $status -ne 0 ]; then + echo "Failed to start mongod: $status" + sync + cat $LOGS_PATH/mongod.log + exit $status fi - echo "Try to reconnect to nats(${NATS_HOST}) $i" - sleep 1 -done - -# mongo -echo "starting mongod" -cat $DIAL_FILE_CERT_DIR_PATH/$DIAL_FILE_CERT_NAME > $DIAL_FILE_CERT_DIR_PATH/mongo.key -cat $DIAL_FILE_CERT_DIR_PATH/$DIAL_FILE_CERT_KEY_NAME >> $DIAL_FILE_CERT_DIR_PATH/mongo.key -mongod --setParameter maxNumActiveUserIndexBuilds=64 --port $MONGO_PORT --dbpath $MONGO_PATH --sslMode requireSSL --sslCAFile $CA_POOL_CERT_PATH --sslPEMKeyFile $DIAL_FILE_CERT_DIR_PATH/mongo.key >$LOGS_PATH/mongod.log 2>&1 & -status=$? -mongo_pid=$! -if [ $status -ne 0 ]; then - echo "Failed to start mongod: $status" - sync - cat $LOGS_PATH/mongod.log - exit $status -fi -# waiting for mongo DB. Without wait, sometimes auth service didn't connect. -i=0 -while true; do - i=$((i+1)) - if openssl s_client -connect ${MONGODB_HOST} -cert ${INTERNAL_CERT_DIR_PATH}/${DIAL_FILE_CERT_NAME} -key ${INTERNAL_CERT_DIR_PATH}/${DIAL_FILE_CERT_KEY_NAME} <<< "Q" 2>/dev/null > /dev/null; then - break + # waiting for mongo DB. Without wait, sometimes auth service didn't connect. + i=0 + while [ $i -lt 60 ]; do + i=$((i+1)) + + if [ $i -eq 60 ]; then + echo "Failed to start mongod: timeout" + sync + cat $LOGS_PATH/mongod.log + exit 1 + fi + + if openssl s_client -connect ${MONGODB_HOST} -cert ${INTERNAL_CERT_DIR_PATH}/${DIAL_FILE_CERT_NAME} \ + -key ${INTERNAL_CERT_DIR_PATH}/${DIAL_FILE_CERT_KEY_NAME} <<< "Q" 2>/dev/null > /dev/null; then + break + fi + echo "Try to reconnect to mongodb(${MONGODB_HOST}) $i" + sleep 1 + done + + # needed by coap-gateway.test and grpc-gateway.test + ## LISTEN CERTS + export LISTEN_FILE_CA_POOL="$CA_POOL_CERT_PATH" + export LISTEN_FILE_CERT_DIR_PATH="$INTERNAL_CERT_DIR_PATH" + export LISTEN_FILE_CERT_NAME="$GRPC_INTERNAL_CERT_NAME" + export LISTEN_FILE_CERT_KEY_NAME="$GRPC_INTERNAL_CERT_KEY_NAME" + ## OTHER + export TEST_COAP_GW_CERT_FILE="${EXTERNAL_CERT_DIR_PATH}/${COAP_GATEWAY_FILE_CERT_NAME}" + export TEST_COAP_GW_KEY_FILE="${EXTERNAL_CERT_DIR_PATH}/${COAP_GATEWAY_FILE_CERT_KEY_NAME}" + export TEST_ROOT_CA_CERT="${CA_POOL_CERT_PATH}" + export TEST_ROOT_CA_KEY="${CA_POOL_CERT_KEY_PATH}" + export TEST_CLOUD_SID="${COAP_GATEWAY_CLOUD_ID}" + export TEST_OAUTH_SERVER_ID_TOKEN_PRIVATE_KEY="${OAUTH_ID_TOKEN_KEY_PATH}" + export TEST_OAUTH_SERVER_ACCESS_TOKEN_PRIVATE_KEY="${OAUTH_ACCESS_TOKEN_KEY_PATH}" + export TEST_COAP_GATEWAY_UDP_ENABLED="${COAP_GATEWAY_UDP_ENABLED}" + + if [ "${COAP_GATEWAY_TEST_DISABLED}" != "1" ]; then + opts=() + if [ -n "${COAP_GATEWAY_TEST_RUN}" ]; then + opts+=("-test.run" "${COAP_GATEWAY_TEST_RUN}") + fi + echo "starting coap-gateway test" + coap-gateway.test -test.v -test.timeout 600s -test.parallel 1 ${opts[@]} fi - echo "Try to reconnect to mongodb(${MONGODB_HOST}) $i" - sleep 1 -done -echo "starting grpc-gateway test" -grpc-gateway.test -test.v -test.timeout 600s -test.parallel 1 + if [ "${GRPC_GATEWAY_TEST_DISABLED}" != "1" ]; then + opts=() + if [ -n "${GRPC_GATEWAY_TEST_RUN}" ]; then + opts+=("-test.run" "${GRPC_GATEWAY_TEST_RUN}") + fi + echo "starting grpc-gateway test" + grpc-gateway.test -test.v -test.timeout 600s -test.parallel 1 ${opts[@]} + fi -echo "starting test/iotivity-lite test" -test-iotivity-lite.test -test.v -test.timeout 600s -test.parallel 1 + if [ "${IOTIVITY_LITE_TEST_DISABLED}" != "1" ]; then + opts=() + if [ -n "${IOTIVITY_LITE_TEST_RUN}" ]; then + opts+=("-test.run" "${IOTIVITY_LITE_TEST_RUN}") + fi + echo "starting test/iotivity-lite test" + test-iotivity-lite.test -test.v -test.timeout 600s -test.parallel 1 ${opts[@]} + fi +fi diff --git a/test/coap-gateway/service/resourceDirectory.go b/test/coap-gateway/service/resourceDirectory.go index 3188fe7e9..d14a81d0d 100644 --- a/test/coap-gateway/service/resourceDirectory.go +++ b/test/coap-gateway/service/resourceDirectory.go @@ -1,6 +1,7 @@ package service import ( + "errors" "fmt" "net/url" "regexp" @@ -58,7 +59,7 @@ func resourceDirectoryPublishHandler(req *mux.Message, client *Client) { } p.SequenceNumber = req.Sequence() - if err := client.handler.PublishResources(p); err != nil { + if err = client.handler.PublishResources(p); err != nil { client.logAndWriteErrorResponse(err, coapCodes.InternalServerError, req.Token()) return } @@ -99,7 +100,7 @@ func parseUnpublishRequestFromQuery(queries []string) (UnpublishRequest, error) } if req.DeviceID == "" { - return UnpublishRequest{}, fmt.Errorf("deviceID not found") + return UnpublishRequest{}, errors.New("deviceID not found") } return req, nil diff --git a/test/coap-gateway/service/service.go b/test/coap-gateway/service/service.go index 9d407c989..9586308ef 100644 --- a/test/coap-gateway/service/service.go +++ b/test/coap-gateway/service/service.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "os" "os/signal" @@ -154,7 +155,7 @@ func validateCommand(s mux.ResponseWriter, req *mux.Message, server *Service, fn fnc(req, client) case coapCodes.Empty: if !ok { - client.logAndWriteErrorResponse(fmt.Errorf("cannot handle command: client not found"), coapCodes.InternalServerError, req.Token()) + client.logAndWriteErrorResponse(errors.New("cannot handle command: client not found"), coapCodes.InternalServerError, req.Token()) closeClient(client) return } diff --git a/test/coap-gateway/test/defaultHandler.go b/test/coap-gateway/test/defaultHandler.go index 12a2fec30..65c6f4078 100644 --- a/test/coap-gateway/test/defaultHandler.go +++ b/test/coap-gateway/test/defaultHandler.go @@ -100,15 +100,15 @@ func (h *DefaultObserverHandler) RefreshToken(req coapgwService.CoapRefreshToken }, nil } -func (h *DefaultObserverHandler) OnObserveResource(_ context.Context, deviceID, resourceHref string, notification *pool.Message) error { - log.Debugf("OnObserveResource: %v%v", deviceID, resourceHref) +func (h *DefaultObserverHandler) OnObserveResource(_ context.Context, deviceID, resourceHref string, resourceTypes []string, notification *pool.Message) error { + log.Debugf("OnObserveResource: %v%v %v", deviceID, resourceHref, resourceTypes) msg := message.ToJson(notification, true, true) log.Get().With("notification", msg).Debug("RECEIVED-OBSERVE") return nil } -func (h *DefaultObserverHandler) OnGetResourceContent(_ context.Context, deviceID, resourceHref string, notification *pool.Message) error { - log.Debugf("OnGetResourceContent: %v%v", deviceID, resourceHref) +func (h *DefaultObserverHandler) OnGetResourceContent(_ context.Context, deviceID, resourceHref string, resourceTypes []string, notification *pool.Message) error { + log.Debugf("OnGetResourceContent: %v%v %v", deviceID, resourceHref, resourceTypes) msg := message.ToJson(notification, true, false) log.Get().With("notification", msg).Debug("RECEIVED-GET") return nil diff --git a/test/device/bridge/device.go b/test/device/bridge/device.go new file mode 100644 index 000000000..80af77d79 --- /dev/null +++ b/test/device/bridge/device.go @@ -0,0 +1,102 @@ +/**************************************************************************** + * + * Copyright (c) 2024 plgd.dev s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +package bridge + +import ( + "time" + + "github.com/plgd-dev/device/v2/bridge/resources/thingDescription" + bridgeDevice "github.com/plgd-dev/device/v2/cmd/bridge-device/device" + "github.com/plgd-dev/device/v2/schema" + schemaDevice "github.com/plgd-dev/device/v2/schema/device" + "github.com/plgd-dev/device/v2/schema/interfaces" + "github.com/plgd-dev/device/v2/schema/maintenance" + "github.com/plgd-dev/hub/v2/test/device" + "github.com/plgd-dev/hub/v2/test/sdk" +) + +var TestResources = []schema.ResourceLink{ + { + Href: schemaDevice.ResourceURI, + ResourceTypes: []string{bridgeDevice.DeviceResourceType, schemaDevice.ResourceType}, + Interfaces: []string{interfaces.OC_IF_BASELINE, interfaces.OC_IF_R}, + Policy: &schema.Policy{ + BitMask: schema.Discoverable, + }, + }, + { + Href: maintenance.ResourceURI, + ResourceTypes: []string{maintenance.ResourceType}, + Interfaces: []string{interfaces.OC_IF_BASELINE, interfaces.OC_IF_RW}, + Policy: &schema.Policy{ + BitMask: schema.Discoverable, + }, + }, +} + +type Device struct { + device.BaseDevice + testResources int // number of test resources + tdEnabled bool // thingDescription resource enabled +} + +func NewDevice(id, name string, testResources int, tdEnabled bool) *Device { + return &Device{ + BaseDevice: device.MakeBaseDevice(id, name), + testResources: testResources, + tdEnabled: tdEnabled, + } +} + +func (d *Device) GetType() device.Type { + return device.Bridged +} + +func (d *Device) GetSDKClientOptions() []sdk.Option { + return []sdk.Option{sdk.WithUseDeviceIDInQuery(true)} +} + +func (d *Device) GetRetryInterval(int) time.Duration { + return time.Second * 10 +} + +func (d *Device) GetDefaultResources() schema.ResourceLinks { + testResources := TestResources + for i := 0; i < d.testResources; i++ { + testResources = append(testResources, schema.ResourceLink{ + Href: bridgeDevice.GetTestResourceHref(i), + ResourceTypes: []string{bridgeDevice.TestResourceType}, + Interfaces: []string{interfaces.OC_IF_BASELINE, interfaces.OC_IF_RW}, + Policy: &schema.Policy{ + BitMask: schema.Discoverable | schema.Observable, + }, + }) + } + if d.tdEnabled { + testResources = append(testResources, schema.ResourceLink{ + Href: thingDescription.ResourceURI, + ResourceTypes: []string{thingDescription.ResourceType}, + Interfaces: []string{interfaces.OC_IF_BASELINE, interfaces.OC_IF_R}, + Policy: &schema.Policy{ + BitMask: schema.Discoverable | schema.Observable, + }, + }) + } + return testResources +} diff --git a/test/device/device.go b/test/device/device.go new file mode 100644 index 000000000..de3e9d92c --- /dev/null +++ b/test/device/device.go @@ -0,0 +1,164 @@ +/**************************************************************************** + * + * Copyright (c) 2024 plgd.dev s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +package device + +import ( + "context" + "errors" + "fmt" + "log" + "sync/atomic" + "time" + + "github.com/plgd-dev/device/v2/client/core" + deviceCoap "github.com/plgd-dev/device/v2/pkg/net/coap" + "github.com/plgd-dev/device/v2/schema" + "github.com/plgd-dev/device/v2/schema/device" + "github.com/plgd-dev/hub/v2/test/sdk" +) + +type Type int + +const ( + OCF Type = iota + Bridged +) + +type Device interface { + // GetType returns device type + GetType() Type + + // GetID returns device ID + GetID() string + + // SetID sets device ID + SetID(id string) + + // GetName returns device name + GetName() string + + // GetRetryInterval returns retry interval of the device before retrying provisioning + GetRetryInterval(attempt int) time.Duration + + // GetDefaultResources returns default device resources + GetDefaultResources() schema.ResourceLinks + + // GetSDKClientOptions returns options for the SDK client used with this device + GetSDKClientOptions() []sdk.Option +} + +type BaseDevice struct { + id string + name string +} + +func MakeBaseDevice(id, name string) BaseDevice { + return BaseDevice{ + id: id, + name: name, + } +} + +func (bd *BaseDevice) GetID() string { + return bd.id +} + +func (bd *BaseDevice) SetID(id string) { + bd.id = id +} + +func (bd *BaseDevice) GetName() string { + return bd.name +} + +func (bd *BaseDevice) GetSDKClientOptions() []sdk.Option { + return nil +} + +type GetResourceOpts func(*core.Device) deviceCoap.OptionFunc + +func FindDeviceByName(ctx context.Context, name string, getResourceOpts ...GetResourceOpts) (deviceID string, _ error) { + client := core.NewClient() + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + h := findDeviceIDByNameHandler{ + name: name, + cancel: cancel, + getResourceOptions: getResourceOpts, + } + + err := client.GetDevicesByMulticast(ctx, core.DefaultDiscoveryConfiguration(), &h) + if err != nil { + return "", fmt.Errorf("could not find the device named %s: %w", name, err) + } + id, ok := h.id.Load().(string) + if !ok || id == "" { + return "", fmt.Errorf("could not find the device named %s: not found", name) + } + return id, nil +} + +type findDeviceIDByNameHandler struct { + id atomic.Value + name string + cancel context.CancelFunc + getResourceOptions []GetResourceOpts +} + +func (h *findDeviceIDByNameHandler) Handle(ctx context.Context, dev *core.Device) { + defer func() { + if errC := dev.Close(ctx); errC != nil { + h.Error(errC) + } + }() + deviceLinks, err := dev.GetResourceLinks(ctx, dev.GetEndpoints()) + if err != nil { + h.Error(err) + return + } + l, ok := deviceLinks.GetResourceLink(device.ResourceURI) + if !ok { + return + } + var d device.Device + var getResourceOpts []deviceCoap.OptionFunc + if h.getResourceOptions != nil { + for _, opts := range h.getResourceOptions { + getResourceOpts = append(getResourceOpts, opts(dev)) + } + } + err = dev.GetResource(ctx, l, &d, getResourceOpts...) + if err != nil { + h.Error(err) + return + } + if d.Name == h.name { + h.id.Store(d.ID) + h.cancel() + } +} + +func (h *findDeviceIDByNameHandler) Error(err error) { + if errors.Is(err, context.Canceled) { + return + } + log.Printf("find device ID by name handler error: %v", err.Error()) +} diff --git a/test/device/ocf/device.go b/test/device/ocf/device.go new file mode 100644 index 000000000..3000bfea4 --- /dev/null +++ b/test/device/ocf/device.go @@ -0,0 +1,133 @@ +/**************************************************************************** + * + * Copyright (c) 2024 plgd.dev s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +package ocf + +import ( + "math" + "time" + + "github.com/plgd-dev/device/v2/schema" + "github.com/plgd-dev/device/v2/schema/collection" + "github.com/plgd-dev/device/v2/schema/configuration" + schemaDevice "github.com/plgd-dev/device/v2/schema/device" + "github.com/plgd-dev/device/v2/schema/interfaces" + "github.com/plgd-dev/device/v2/schema/maintenance" + "github.com/plgd-dev/device/v2/schema/platform" + "github.com/plgd-dev/device/v2/schema/plgdtime" + "github.com/plgd-dev/device/v2/schema/softwareupdate" + "github.com/plgd-dev/device/v2/test/resource/types" + "github.com/plgd-dev/hub/v2/test/device" +) + +var TestResources = []schema.ResourceLink{ + { + Href: platform.ResourceURI, + ResourceTypes: []string{platform.ResourceType}, + Interfaces: []string{interfaces.OC_IF_R, interfaces.OC_IF_BASELINE}, + Policy: &schema.Policy{ + BitMask: 3, + }, + }, + + { + Href: schemaDevice.ResourceURI, + ResourceTypes: []string{types.DEVICE_CLOUD, schemaDevice.ResourceType}, + Interfaces: []string{interfaces.OC_IF_R, interfaces.OC_IF_BASELINE}, + Policy: &schema.Policy{ + BitMask: 3, + }, + }, + + { + Href: configuration.ResourceURI, + ResourceTypes: []string{configuration.ResourceType}, + Interfaces: []string{interfaces.OC_IF_RW, interfaces.OC_IF_BASELINE}, + Policy: &schema.Policy{ + BitMask: 3, + }, + }, + + { + Href: "/light/1", + ResourceTypes: []string{types.CORE_LIGHT}, + Interfaces: []string{interfaces.OC_IF_RW, interfaces.OC_IF_BASELINE}, + Policy: &schema.Policy{ + BitMask: 3, + }, + }, + + { + Href: "/switches", + ResourceTypes: []string{collection.ResourceType}, + Interfaces: []string{interfaces.OC_IF_LL, interfaces.OC_IF_CREATE, interfaces.OC_IF_B, interfaces.OC_IF_BASELINE}, + Policy: &schema.Policy{ + BitMask: 3, + }, + }, + + { + Href: maintenance.ResourceURI, + ResourceTypes: []string{maintenance.ResourceType}, + Interfaces: []string{interfaces.OC_IF_RW, interfaces.OC_IF_BASELINE}, + Policy: &schema.Policy{ + BitMask: 1, + }, + }, + + { + Href: plgdtime.ResourceURI, + ResourceTypes: []string{plgdtime.ResourceType}, + Interfaces: []string{interfaces.OC_IF_RW, interfaces.OC_IF_BASELINE}, + Policy: &schema.Policy{ + BitMask: 3, + }, + }, + + { + Href: softwareupdate.ResourceURI, + ResourceTypes: []string{softwareupdate.ResourceType}, + Interfaces: []string{interfaces.OC_IF_RW, interfaces.OC_IF_BASELINE}, + Policy: &schema.Policy{ + BitMask: 3, + }, + }, +} + +type Device struct { + device.BaseDevice +} + +func NewDevice(id, name string) *Device { + return &Device{ + BaseDevice: device.MakeBaseDevice(id, name), + } +} + +func (d *Device) GetType() device.Type { + return device.OCF +} + +func (d *Device) GetRetryInterval(attempt int) time.Duration { + /* [2s, 4s, 8s, 16s, 32s, 64s] */ + return time.Duration(math.Exp2(float64(attempt))) * time.Second +} + +func (d *Device) GetDefaultResources() schema.ResourceLinks { + return TestResources +} diff --git a/test/http/request.go b/test/http/request.go index 96f6ef4da..17f64a5a8 100644 --- a/test/http/request.go +++ b/test/http/request.go @@ -3,6 +3,7 @@ package http import ( "context" "crypto/tls" + "errors" "fmt" "io" "net/http" @@ -42,7 +43,7 @@ func NewHTTPRequest(method, url string, body io.Reader) *HTTPRequestBuilder { } func (c *HTTPRequestBuilder) AuthToken(token string) *HTTPRequestBuilder { - c.header["Authorization"] = fmt.Sprintf("bearer %s", token) + c.header["Authorization"] = "bearer " + token return c } @@ -143,8 +144,8 @@ func DoHTTPRequest(t *testing.T, req *http.Request) *http.Response { } func ReadHTTPResponse(t *testing.T, w io.Reader, contentType string, data interface{}) { - readFrom := func(w io.Reader, v interface{}) error { - return fmt.Errorf("not supported") + readFrom := func(_ io.Reader, _ interface{}) error { + return errors.New("not supported") } switch contentType { case message.AppJSON.String(): @@ -159,7 +160,7 @@ func ReadHTTPResponse(t *testing.T, w io.Reader, contentType string, data interf } val := reflect.ValueOf(v) if val.Kind() != reflect.Ptr { - return fmt.Errorf("some: check must be a pointer") + return errors.New("some: check must be a pointer") } val.Elem().Set(reflect.ValueOf(string(b))) return nil diff --git a/test/iotivity-lite/service/deleteResource_test.go b/test/iotivity-lite/service/deleteResource_test.go index 090083ac6..185fdd616 100644 --- a/test/iotivity-lite/service/deleteResource_test.go +++ b/test/iotivity-lite/service/deleteResource_test.go @@ -20,6 +20,7 @@ import ( "github.com/plgd-dev/hub/v2/test/config" iotService "github.com/plgd-dev/hub/v2/test/iotivity-lite/service" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" + "github.com/plgd-dev/hub/v2/test/sdk" "github.com/plgd-dev/hub/v2/test/service" "github.com/stretchr/testify/require" "golang.org/x/exp/maps" @@ -142,7 +143,7 @@ func TestBatchDeleteResources(t *testing.T) { }, func(unpublished map[int64]struct{}) bool { return len(unpublished) == numSwitches }) - getHandler := func(s *coapgwTestService.Service, opts ...coapgwTestService.Option) coapgwTestService.ServiceHandler { + getHandler := func(*coapgwTestService.Service, ...coapgwTestService.Option) coapgwTestService.ServiceHandler { return bh } @@ -161,7 +162,7 @@ func TestBatchDeleteResources(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -173,13 +174,13 @@ func TestBatchDeleteResources(t *testing.T) { // TODO: copy services initialization from the real coap-gw to the mock coap-gw, // for now we must force TCP when mock coap-gw is used // _, _ = test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) - _, _ = test.OnboardDevSim(ctx, t, c, deviceID, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) + _, shutdown := test.OnboardDevSim(ctx, t, c, deviceID, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) require.True(t, bh.WaitForFirstSignIn(time.Second*20)) t.Cleanup(func() { - test.DisownDevice(t, deviceID) + shutdown() }) - devClient, err := test.NewSDKClient() + devClient, err := sdk.NewClient() require.NoError(t, err) defer func() { _ = devClient.Close(ctx) diff --git a/test/iotivity-lite/service/offboard_test.go b/test/iotivity-lite/service/offboard_test.go index 6aec76563..7a44b2571 100644 --- a/test/iotivity-lite/service/offboard_test.go +++ b/test/iotivity-lite/service/offboard_test.go @@ -3,7 +3,7 @@ package service_test import ( "context" "crypto/tls" - "fmt" + "errors" "strings" "sync" "testing" @@ -21,7 +21,6 @@ import ( iotService "github.com/plgd-dev/hub/v2/test/iotivity-lite/service" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" "github.com/plgd-dev/hub/v2/test/service" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/atomic" "google.golang.org/grpc" @@ -30,7 +29,7 @@ import ( // signed in -> deregister by sending DELETE request func TestOffboard(t *testing.T) { - deviceID := test.MustFindDeviceByName(test.TestDeviceName) + d := test.MustFindTestDevice() deadline := time.Now().Add(time.Minute) ctx, cancel := context.WithDeadline(context.Background(), deadline) @@ -41,7 +40,7 @@ func TestOffboard(t *testing.T) { defer tearDown() ch := iotService.NewCoapHandlerWithCounter(0) - makeHandler := func(s *coapgwTestService.Service, opts ...coapgwTestService.Option) coapgwTestService.ServiceHandler { + makeHandler := func(*coapgwTestService.Service, ...coapgwTestService.Option) coapgwTestService.ServiceHandler { return ch } @@ -50,13 +49,13 @@ func TestOffboard(t *testing.T) { log.Debugf("%+v", h.CallCounter.Data) signInCount, ok := h.CallCounter.Data[iotService.SignInKey] require.True(t, ok) - require.True(t, signInCount > 0) + require.Greater(t, signInCount, 0) publishCount, ok := h.CallCounter.Data[iotService.PublishKey] require.True(t, ok) require.Equal(t, 1, publishCount) singOffCount, ok := h.CallCounter.Data[iotService.SignOffKey] require.True(t, ok) - require.True(t, singOffCount > 0) + require.Greater(t, singOffCount, 0) } coapShutdown := coapgwTest.SetUp(t, makeHandler, validateHandler) @@ -64,7 +63,7 @@ func TestOffboard(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -75,14 +74,14 @@ func TestOffboard(t *testing.T) { // TODO: copy services initialization from the real coap-gw to the mock coap-gw, // for now we must force TCP when mock coap-gw is used - // _, _ = test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) - _, _ = test.OnboardDevSim(ctx, t, c, deviceID, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) + // shutdown := test.OnboardDevice(ctx, t, c, d, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) + shutdown := test.OnboardDevice(ctx, t, c, d, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) require.True(t, ch.WaitForFirstSignIn(time.Second*20)) t.Cleanup(func() { - test.DisownDevice(t, deviceID) + shutdown() }) - test.OffBoardDevSim(ctx, t, deviceID) + test.OffboardDevice(ctx, t, d) require.True(t, ch.WaitForFirstSignOff(time.Second*20)) } @@ -120,7 +119,7 @@ func (sh *switchableHandler) blockSignInChannel() chan struct{} { func (sh *switchableHandler) SignIn(req coapgwService.CoapSignInReq) (coapgwService.CoapSignInResp, error) { resp, err := sh.CoapHandlerWithCounter.SignIn(req) if sh.failSignIn.Load() { - return coapgwService.CoapSignInResp{}, fmt.Errorf("sign in disabled") + return coapgwService.CoapSignInResp{}, errors.New("sign in disabled") } b := sh.blockSignInChannel() if b != nil { @@ -146,7 +145,7 @@ func (sh *switchableHandler) blockSignOff() chan struct{} { func (sh *switchableHandler) SignOff() error { err := sh.CoapHandlerWithCounter.SignOff() if sh.failSignOff.Load() { - return fmt.Errorf("sign off disabled") + return errors.New("sign off disabled") } b := sh.blockSignOffChannel() if b != nil { @@ -172,7 +171,7 @@ func (sh *switchableHandler) blockRefresh() chan struct{} { func (sh *switchableHandler) RefreshToken(req coapgwService.CoapRefreshTokenReq) (coapgwService.CoapRefreshTokenResp, error) { resp, err := sh.CoapHandlerWithCounter.RefreshToken(req) if sh.failRefreshToken.Load() { - return coapgwService.CoapRefreshTokenResp{}, fmt.Errorf("refresh token disabled") + return coapgwService.CoapRefreshTokenResp{}, errors.New("refresh token disabled") } b := sh.blockRefreshChannel() if b != nil { @@ -183,7 +182,7 @@ func (sh *switchableHandler) RefreshToken(req coapgwService.CoapRefreshTokenReq) // not signed in, with permanent and short access-token -> deregister by sending DELETE request with access token func TestOffboardWithoutSignIn(t *testing.T) { - deviceID := test.MustFindDeviceByName(test.TestDeviceName) + d := test.MustFindTestDevice() deadline := time.Now().Add(time.Minute) ctx, cancel := context.WithDeadline(context.Background(), deadline) @@ -195,7 +194,7 @@ func TestOffboardWithoutSignIn(t *testing.T) { sh := NewSwitchableHandler(-1) sh.failSignIn.Store(true) - makeHandler := func(s *coapgwTestService.Service, opts ...coapgwTestService.Option) coapgwTestService.ServiceHandler { + makeHandler := func(*coapgwTestService.Service, ...coapgwTestService.Option) coapgwTestService.ServiceHandler { return sh } @@ -206,19 +205,8 @@ func TestOffboardWithoutSignIn(t *testing.T) { log.Debugf("%+v", h.CallCounter.Data) signInCount, ok := h.CallCounter.Data[iotService.SignInKey] require.True(t, ok) - // sometimes the first sign-in attempt fails, so we allow 2 attempts - /* - === RUN TestOffboardWithoutSignIn - offboard_test.go:205: - Error Trace: /src/github.com/plgd-dev/hub/test/iotivity-lite/service/offboard_test.go:205 - /src/github.com/plgd-dev/hub/test/coap-gateway/test/test.go:59 - /src/github.com/plgd-dev/hub/test/iotivity-lite/service/offboard_test.go:236 - Error: Not equal: - expected: 1 - actual : 2 - Test: TestOffboardWithoutSignIn - */ - require.True(t, signInCount >= 1 || signInCount <= 2) + // depending on the timing of the test, the sign-in may be called once or twice + require.True(t, signInCount >= 1 && signInCount <= 2) _, ok = h.CallCounter.Data[iotService.RefreshTokenKey] require.False(t, ok) signOffCount, ok := h.CallCounter.Data[iotService.SignOffKey] @@ -231,7 +219,7 @@ func TestOffboardWithoutSignIn(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -240,22 +228,22 @@ func TestOffboardWithoutSignIn(t *testing.T) { }() c := pb.NewGrpcGatewayClient(conn) - // deviceID, _ = test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) - deviceID, _ = test.OnboardDevSim(ctx, t, c, deviceID, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) + // shutdown := test.OnboardDevSim(ctx, t, c, d, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) + shutdown := test.OnboardDevice(ctx, t, c, d, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) t.Cleanup(func() { - test.DisownDevice(t, deviceID) + shutdown() }) require.True(t, sh.WaitForFirstSignIn(time.Second*20)) // first retry after failure is after 2 seconds, so hopefully it doesn't trigger, if this test // behaves flakily then we will have to update simulator to have a configurable retry sh.failSignIn.Store(false) - // wait for sign-in to be called again - time.Sleep(time.Second * 3) - test.OffBoardDevSim(ctx, t, deviceID) + time.Sleep(d.GetRetryInterval(1) + time.Second) + test.OffboardDevice(ctx, t, d) require.True(t, sh.WaitForFirstSignOff(time.Second*20)) } // not signed in, with permanent but long access-token -> try to sign in and then deregister without access token +// OCF device specific behavior func TestOffboardWithSignIn(t *testing.T) { deviceID := test.MustFindDeviceByName(test.TestDeviceName) @@ -270,7 +258,7 @@ func TestOffboardWithSignIn(t *testing.T) { sh := NewSwitchableHandler(-1) sh.failSignIn.Store(true) sh.SetAccessToken(strings.Repeat("this-access-token-is-so-long-that-its-size-is-longer-than-the-allowed-request-header-size", 5)) - makeHandler := func(s *coapgwTestService.Service, opts ...coapgwTestService.Option) coapgwTestService.ServiceHandler { + makeHandler := func(*coapgwTestService.Service, ...coapgwTestService.Option) coapgwTestService.ServiceHandler { return sh } @@ -294,7 +282,7 @@ func TestOffboardWithSignIn(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -303,10 +291,10 @@ func TestOffboardWithSignIn(t *testing.T) { }() c := pb.NewGrpcGatewayClient(conn) - // deviceID, _ = test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) - deviceID, _ = test.OnboardDevSim(ctx, t, c, deviceID, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) + // deviceID, shutdown := test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) + deviceID, shutdown := test.OnboardDevSim(ctx, t, c, deviceID, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) t.Cleanup(func() { - test.DisownDevice(t, deviceID) + shutdown() }) require.True(t, sh.WaitForFirstSignIn(time.Second*20)) @@ -320,6 +308,7 @@ func TestOffboardWithSignIn(t *testing.T) { } // not signed up, with refresh token -> try to login and then deregister without access token +// OCF device specific behavior func TestOffboardWithSignInByRefreshToken(t *testing.T) { deviceID := test.MustFindDeviceByName(test.TestDeviceName) @@ -334,7 +323,7 @@ func TestOffboardWithSignInByRefreshToken(t *testing.T) { sh := NewSwitchableHandler(20) sh.failSignIn.Store(true) sh.SetAccessToken(strings.Repeat("this-access-token-is-so-long-that-its-size-is-longer-than-the-allowed-request-header-size", 5)) - makeHandler := func(s *coapgwTestService.Service, opts ...coapgwTestService.Option) coapgwTestService.ServiceHandler { + makeHandler := func(*coapgwTestService.Service, ...coapgwTestService.Option) coapgwTestService.ServiceHandler { return sh } @@ -344,21 +333,21 @@ func TestOffboardWithSignInByRefreshToken(t *testing.T) { defer h.CallCounter.Lock.Unlock() log.Debugf("%+v", h.CallCounter.Data) signInCount, ok := h.CallCounter.Data[iotService.SignInKey] - assert.True(t, ok) - assert.True(t, signInCount > 1) + require.True(t, ok) + require.Greater(t, signInCount, 1) refreshCount, ok := h.CallCounter.Data[iotService.RefreshTokenKey] - assert.True(t, ok) - assert.True(t, refreshCount > 0) + require.True(t, ok) + require.Greater(t, refreshCount, 0) signOffCount, ok := h.CallCounter.Data[iotService.SignOffKey] - assert.True(t, ok) - assert.Equal(t, 1, signOffCount) + require.True(t, ok) + require.Equal(t, 1, signOffCount) } - coapShutdown := coapgwTest.SetUp(t, makeHandler, func(handler coapgwTestService.ServiceHandler) {}) + coapShutdown := coapgwTest.SetUp(t, makeHandler, func(coapgwTestService.ServiceHandler) {}) ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -369,9 +358,9 @@ func TestOffboardWithSignInByRefreshToken(t *testing.T) { // register device first time // deviceID, _ = test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) - deviceID, _ = test.OnboardDevSim(ctx, t, c, deviceID, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) + deviceID, shutdown := test.OnboardDevSim(ctx, t, c, deviceID, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) t.Cleanup(func() { - test.DisownDevice(t, deviceID) + shutdown() }) require.True(t, sh.WaitForFirstSignIn(time.Second*20)) @@ -398,7 +387,7 @@ func TestOffboardWithSignInByRefreshToken(t *testing.T) { // Multiple offboard attempts should be ignored func TestOffboardWithRepeat(t *testing.T) { - deviceID := test.MustFindDeviceByName(test.TestDeviceName) + d := test.MustFindTestDevice() deadline := time.Now().Add(time.Minute) ctx, cancel := context.WithDeadline(context.Background(), deadline) @@ -410,7 +399,7 @@ func TestOffboardWithRepeat(t *testing.T) { sh := NewSwitchableHandler(-1) sh.blockSignOff() - makeHandler := func(s *coapgwTestService.Service, opts ...coapgwTestService.Option) coapgwTestService.ServiceHandler { + makeHandler := func(*coapgwTestService.Service, ...coapgwTestService.Option) coapgwTestService.ServiceHandler { return sh } @@ -429,7 +418,7 @@ func TestOffboardWithRepeat(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -439,17 +428,17 @@ func TestOffboardWithRepeat(t *testing.T) { c := pb.NewGrpcGatewayClient(conn) // deviceID, _ = test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) - deviceID, _ = test.OnboardDevSim(ctx, t, c, deviceID, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) + shutdown := test.OnboardDevice(ctx, t, c, d, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) t.Cleanup(func() { - test.DisownDevice(t, deviceID) + shutdown() }) require.True(t, sh.WaitForFirstSignIn(time.Second*20)) time.Sleep(time.Second) - test.OffBoardDevSim(ctx, t, deviceID) - test.OffBoardDevSim(ctx, t, deviceID) - test.OffBoardDevSim(ctx, t, deviceID) + test.OffboardDevice(ctx, t, d) + test.OffboardDevice(ctx, t, d) + test.OffboardDevice(ctx, t, d) require.True(t, sh.WaitForFirstSignOff(time.Second*20)) // first SignOff should timeout after 10 secs, we wait 10 additional seconds for the other @@ -458,6 +447,7 @@ func TestOffboardWithRepeat(t *testing.T) { } // Onboarding should interrupt an ongoing offboarding +// OCF device specific behavior func TestOffboardInterrupt(t *testing.T) { deviceID := test.MustFindDeviceByName(test.TestDeviceName) @@ -476,7 +466,7 @@ func TestOffboardInterrupt(t *testing.T) { // off-boarding will try login by refresh token, but block the sending of response blockRefreshCh := sh.blockRefresh() - makeHandler := func(s *coapgwTestService.Service, opts ...coapgwTestService.Option) coapgwTestService.ServiceHandler { + makeHandler := func(*coapgwTestService.Service, ...coapgwTestService.Option) coapgwTestService.ServiceHandler { return sh } @@ -493,7 +483,7 @@ func TestOffboardInterrupt(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) diff --git a/test/iotivity-lite/service/republish_test.go b/test/iotivity-lite/service/republish_test.go index 70d7f0bec..9e43def74 100644 --- a/test/iotivity-lite/service/republish_test.go +++ b/test/iotivity-lite/service/republish_test.go @@ -23,7 +23,7 @@ import ( ) func TestRepublishAfterRefresh(t *testing.T) { - deviceID := test.MustFindDeviceByName(test.TestDeviceName) + d := test.MustFindTestDevice() atLifetime := time.Second * 20 deadline := time.Now().Add(time.Minute) @@ -34,7 +34,7 @@ func TestRepublishAfterRefresh(t *testing.T) { tearDown := service.SetUpServices(ctx, t, services) defer tearDown() - makeHandler := func(s *coapgwTestService.Service, opts ...coapgwTestService.Option) coapgwTestService.ServiceHandler { + makeHandler := func(*coapgwTestService.Service, ...coapgwTestService.Option) coapgwTestService.ServiceHandler { return iotService.NewCoapHandlerWithCounter(int64(atLifetime.Seconds())) } validateHandler := func(handler coapgwTestService.ServiceHandler) { @@ -42,10 +42,10 @@ func TestRepublishAfterRefresh(t *testing.T) { log.Debugf("%+v", h.CallCounter.Data) signInCount, ok := h.CallCounter.Data[iotService.SignInKey] require.True(t, ok) - require.True(t, signInCount > 1) + require.Greater(t, signInCount, 1) refreshCount, ok := h.CallCounter.Data[iotService.RefreshTokenKey] require.True(t, ok) - require.True(t, refreshCount > 0) + require.Greater(t, refreshCount, 0) publishCount, ok := h.CallCounter.Data[iotService.PublishKey] require.True(t, ok) require.Equal(t, 1, publishCount) @@ -56,7 +56,7 @@ func TestRepublishAfterRefresh(t *testing.T) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -65,8 +65,8 @@ func TestRepublishAfterRefresh(t *testing.T) { }() c := pb.NewGrpcGatewayClient(conn) - // _, shutdownDevSim := test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) - _, shutdownDevSim := test.OnboardDevSim(ctx, t, c, deviceID, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) + // shutdownDevSim := test.OnboardDevice(ctx, t, c, d, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil) + shutdownDevSim := test.OnboardDevice(ctx, t, c, d, string(schema.TCPSecureScheme)+"://"+config.COAP_GW_HOST, nil) defer shutdownDevSim() for { diff --git a/test/oauth-server/service/getJWKs_test.go b/test/oauth-server/service/getJWKs_test.go index 8a7994372..2c3e10792 100644 --- a/test/oauth-server/service/getJWKs_test.go +++ b/test/oauth-server/service/getJWKs_test.go @@ -29,6 +29,6 @@ func getJWKs(t *testing.T) map[string]interface{} { err := json.ReadFrom(res.Body, &body) require.NoError(t, err) require.NotEmpty(t, body["keys"]) - require.Equal(t, 2, len(body["keys"].([]interface{}))) + require.Len(t, body["keys"].([]interface{}), 2) return body } diff --git a/test/oauth-server/service/loadKeys.go b/test/oauth-server/service/loadKeys.go index 908199024..683dadf40 100644 --- a/test/oauth-server/service/loadKeys.go +++ b/test/oauth-server/service/loadKeys.go @@ -3,7 +3,7 @@ package service import ( "crypto/x509" "encoding/pem" - "fmt" + "errors" "github.com/plgd-dev/hub/v2/pkg/config/property/urischeme" ) @@ -15,7 +15,7 @@ func LoadPrivateKey(path urischeme.URIScheme) (interface{}, error) { } certDERBlock, _ := pem.Decode(certPEMBlock) if certDERBlock == nil { - return nil, fmt.Errorf("cannot decode pem block") + return nil, errors.New("cannot decode pem block") } if key, err := x509.ParsePKCS8PrivateKey(certDERBlock.Bytes); err == nil { @@ -27,5 +27,5 @@ func LoadPrivateKey(path urischeme.URIScheme) (interface{}, error) { if key, err := x509.ParsePKCS1PrivateKey(certDERBlock.Bytes); err == nil { return key, nil } - return nil, fmt.Errorf("unknown type") + return nil, errors.New("unknown type") } diff --git a/test/oauth-server/service/token.go b/test/oauth-server/service/token.go index cd53a91d5..50cd3e0e2 100644 --- a/test/oauth-server/service/token.go +++ b/test/oauth-server/service/token.go @@ -4,6 +4,7 @@ import ( "crypto/rand" "crypto/rsa" "encoding/hex" + "errors" "fmt" "net/http" "strings" @@ -234,7 +235,7 @@ func (requestHandler *RequestHandler) getToken(w http.ResponseWriter, r *http.Re if clientID == "" { clientID, _, ok = r.BasicAuth() if !ok { - writeError(w, fmt.Errorf("authorization header is not set"), http.StatusBadRequest) + writeError(w, errors.New("authorization header is not set"), http.StatusBadRequest) return } } @@ -303,7 +304,7 @@ func (requestHandler *RequestHandler) validateTokenRequest(clientCfg *Client, to return fmt.Errorf("client(%v) not found", tokenReq.ClientID) } if clientCfg.ClientSecret != "" && clientCfg.ClientSecret != tokenReq.Password { - return fmt.Errorf("invalid client secret") + return errors.New("invalid client secret") } if clientCfg.RequiredRedirectURI != "" && clientCfg.RequiredRedirectURI != tokenReq.RedirectURI { return fmt.Errorf("invalid redirect uri(%v)", tokenReq.RedirectURI) diff --git a/test/oauth-server/service/token_test.go b/test/oauth-server/service/token_test.go index 2a148195e..a2ebf51c1 100644 --- a/test/oauth-server/service/token_test.go +++ b/test/oauth-server/service/token_test.go @@ -63,7 +63,7 @@ func TestRequestHandlerGetTokenWithDefaultScopes(t *testing.T) { token := getToken(t, test.ClientTest, "", "", "", code, "", "", "", service.AllowedGrantType_AUTHORIZATION_CODE, http.StatusOK) require.NotEmpty(t, token["access_token"]) - require.Equal(t, token["scope"], service.DefaultScope) + require.Equal(t, service.DefaultScope, token["scope"]) validator := test.GetJWTValidator(fmt.Sprintf("https://%s%s", config.OAUTH_SERVER_HOST, uri.JWKs)) accessToken, err := validator.Parse(token["access_token"]) require.NoError(t, err) @@ -78,7 +78,7 @@ func TestRequestHandlerGetTokenWithCuscomScopes(t *testing.T) { token := getToken(t, test.ClientTest, "", "", "", code, "", "", "", service.AllowedGrantType_AUTHORIZATION_CODE, http.StatusOK) require.NotEmpty(t, token["access_token"]) - require.Equal(t, token["scope"], "r:* w:*") + require.Equal(t, "r:* w:*", token["scope"]) validator := test.GetJWTValidator(fmt.Sprintf("https://%s%s", config.OAUTH_SERVER_HOST, uri.JWKs)) accessToken, err := validator.Parse(token["access_token"]) require.NoError(t, err) @@ -125,7 +125,7 @@ func TestRequestHandlerGetTokenWithValidRequiredParams(t *testing.T) { code := getAuthorize(t, test.ClientTestRequiredParams, "", "http://localhost:7777", "", "r:*", "code", http.StatusFound, false, false) token := getToken(t, test.ClientTestRequiredParams, test.ClientTestRequiredParamsSecret, "", "http://localhost:7777", code, "", "", "", service.AllowedGrantType_AUTHORIZATION_CODE, http.StatusOK) require.NotEmpty(t, token["access_token"]) - require.Equal(t, token["scope"], "r:*") + require.Equal(t, "r:*", token["scope"]) validator := test.GetJWTValidator(fmt.Sprintf("https://%s%s", config.OAUTH_SERVER_HOST, uri.JWKs)) accessToken, err := validator.Parse(token["access_token"]) require.NoError(t, err) @@ -153,7 +153,7 @@ func TestRequestHandlerGetTokenWithValidRefreshToken(t *testing.T) { token := getToken(t, test.ClientTest, test.ClientTestRequiredParamsSecret, "invalidRefreshToken", "http://localhost:7777", "", "refresh-token", "", "", service.AllowedGrantType_REFRESH_TOKEN, http.StatusOK) require.NotEmpty(t, token["access_token"]) - require.Equal(t, token["scope"], service.DefaultScope) + require.Equal(t, service.DefaultScope, token["scope"]) validator := test.GetJWTValidator(fmt.Sprintf("https://%s%s", config.OAUTH_SERVER_HOST, uri.JWKs)) accessToken, err := validator.Parse(token["access_token"]) require.NoError(t, err) @@ -229,12 +229,12 @@ func TestGetRequestHandlerGetTokenWithDeviceIDAndOwnerClaim(t *testing.T) { if tt.wantDeviceID == "" { require.Empty(t, claims[uri.DeviceIDClaimKey]) } else { - require.Equal(t, claims[uri.DeviceIDClaimKey], tt.wantDeviceID) + require.Equal(t, tt.wantDeviceID, claims[uri.DeviceIDClaimKey]) } if tt.wantOwner == "" { require.Empty(t, claims[uri.OwnerClaimKey]) } else { - require.Equal(t, claims[uri.OwnerClaimKey], tt.wantOwner) + require.Equal(t, tt.wantOwner, claims[uri.OwnerClaimKey]) } }) } diff --git a/test/oauth-server/test/test.go b/test/oauth-server/test/test.go index 2f6871671..e91be0e8c 100644 --- a/test/oauth-server/test/test.go +++ b/test/oauth-server/test/test.go @@ -197,7 +197,7 @@ func HTTPDo(t require.TestingT, req *http.Request, followRedirect bool) *http.Re Transport: trans, } if !followRedirect { - c.CheckRedirect = func(req *http.Request, via []*http.Request) error { + c.CheckRedirect = func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse } } diff --git a/test/pb/device.go b/test/pb/device.go index a5c8b641c..652fef0ea 100644 --- a/test/pb/device.go +++ b/test/pb/device.go @@ -18,11 +18,12 @@ func CmpDeviceValues(t *testing.T, expected, got []*pbGrpc.Device) { dev.ProtocolIndependentId = "" dev.Metadata.Connection.Id = "" dev.Metadata.Connection.ConnectedAt = 0 + dev.Metadata.Connection.LocalEndpoints = nil dev.Metadata.Connection.ServiceId = "" - if dev.Metadata.TwinSynchronization != nil { - dev.Metadata.TwinSynchronization.SyncingAt = 0 - dev.Metadata.TwinSynchronization.InSyncAt = 0 - dev.Metadata.TwinSynchronization.CommandMetadata = nil + if dev.GetMetadata().GetTwinSynchronization() != nil { + dev.GetMetadata().GetTwinSynchronization().SyncingAt = 0 + dev.GetMetadata().GetTwinSynchronization().InSyncAt = 0 + dev.GetMetadata().GetTwinSynchronization().CommandMetadata = nil } dev.Data = nil } @@ -61,6 +62,7 @@ func CleanUpDeviceMetadataUpdated(e *events.DeviceMetadataUpdated, resetCorrelat } e.GetConnection().Id = "" e.GetConnection().ConnectedAt = 0 + e.GetConnection().LocalEndpoints = nil } if e.GetTwinSynchronization() != nil { e.GetTwinSynchronization().CommandMetadata = nil @@ -71,7 +73,7 @@ func CleanUpDeviceMetadataUpdated(e *events.DeviceMetadataUpdated, resetCorrelat } func CleanUpDeviceMetadataSnapshotTaken(e *events.DeviceMetadataSnapshotTaken, resetCorrelationID bool) { - CleanUpDeviceMetadataUpdated(e.DeviceMetadataUpdated, resetCorrelationID) + CleanUpDeviceMetadataUpdated(e.GetDeviceMetadataUpdated(), resetCorrelationID) e.EventMetadata = nil } diff --git a/test/pb/event.go b/test/pb/event.go index d56d53812..e32c9d45f 100644 --- a/test/pb/event.go +++ b/test/pb/event.go @@ -13,6 +13,7 @@ import ( "github.com/plgd-dev/hub/v2/resource-aggregate/events" "github.com/plgd-dev/hub/v2/test" oauthService "github.com/plgd-dev/hub/v2/test/oauth-server/service" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -180,10 +181,10 @@ var cleanupEventFn = map[string]func(ev *pb.Event){ getTypeName(&pb.Event_ResourceChanged{}): func(ev *pb.Event) { CleanUpResourceChanged(ev.GetResourceChanged(), false) }, - getTypeName(&pb.Event_OperationProcessed_{}): func(ev *pb.Event) { + getTypeName(&pb.Event_OperationProcessed_{}): func(*pb.Event) { // nothing to do }, - getTypeName(&pb.Event_SubscriptionCanceled_{}): func(ev *pb.Event) { + getTypeName(&pb.Event_SubscriptionCanceled_{}): func(*pb.Event) { // nothing to do }, getTypeName(&pb.Event_ResourceUpdatePending{}): func(ev *pb.Event) { @@ -283,34 +284,34 @@ var compareEventFn = map[string]func(t *testing.T, e, g *pb.Event, cmpInterface getTypeName(&pb.Event_ResourceChanged{}): func(t *testing.T, e, g *pb.Event, cmpInterface string) { CmpResourceChanged(t, e.GetResourceChanged(), g.GetResourceChanged(), cmpInterface) }, - getTypeName(&pb.Event_ResourceUpdatePending{}): func(t *testing.T, e, g *pb.Event, cmpInterface string) { //nolint:unparam + getTypeName(&pb.Event_ResourceUpdatePending{}): func(t *testing.T, e, g *pb.Event, _ string) { CmpResourceUpdatePending(t, e.GetResourceUpdatePending(), g.GetResourceUpdatePending()) }, - getTypeName(&pb.Event_ResourceUpdated{}): func(t *testing.T, e, g *pb.Event, cmpInterface string) { //nolint:unparam + getTypeName(&pb.Event_ResourceUpdated{}): func(t *testing.T, e, g *pb.Event, _ string) { CmpResourceUpdated(t, e.GetResourceUpdated(), g.GetResourceUpdated()) }, - getTypeName(&pb.Event_ResourceRetrievePending{}): func(t *testing.T, e, g *pb.Event, cmpInterface string) { //nolint:unparam + getTypeName(&pb.Event_ResourceRetrievePending{}): func(t *testing.T, e, g *pb.Event, _ string) { CmpResourceRetrievePending(t, e.GetResourceRetrievePending(), g.GetResourceRetrievePending()) }, - getTypeName(&pb.Event_ResourceRetrieved{}): func(t *testing.T, e, g *pb.Event, cmpInterface string) { //nolint:unparam + getTypeName(&pb.Event_ResourceRetrieved{}): func(t *testing.T, e, g *pb.Event, _ string) { CmpResourceRetrieved(t, e.GetResourceRetrieved(), g.GetResourceRetrieved()) }, - getTypeName(&pb.Event_ResourceDeletePending{}): func(t *testing.T, e, g *pb.Event, cmpInterface string) { //nolint:unparam + getTypeName(&pb.Event_ResourceDeletePending{}): func(t *testing.T, e, g *pb.Event, _ string) { CmpResourceDeletePending(t, e.GetResourceDeletePending(), g.GetResourceDeletePending()) }, - getTypeName(&pb.Event_ResourceDeleted{}): func(t *testing.T, e, g *pb.Event, cmpInterface string) { //nolint:unparam + getTypeName(&pb.Event_ResourceDeleted{}): func(t *testing.T, e, g *pb.Event, _ string) { CmpResourceDeleted(t, e.GetResourceDeleted(), g.GetResourceDeleted()) }, - getTypeName(&pb.Event_ResourceCreatePending{}): func(t *testing.T, e, g *pb.Event, cmpInterface string) { //nolint:unparam + getTypeName(&pb.Event_ResourceCreatePending{}): func(t *testing.T, e, g *pb.Event, _ string) { CmpResourceCreatePending(t, e.GetResourceCreatePending(), g.GetResourceCreatePending()) }, - getTypeName(&pb.Event_ResourceCreated{}): func(t *testing.T, e, g *pb.Event, cmpInterface string) { //nolint:unparam + getTypeName(&pb.Event_ResourceCreated{}): func(t *testing.T, e, g *pb.Event, _ string) { CmpResourceCreated(t, e.GetResourceCreated(), g.GetResourceCreated()) }, - getTypeName(&pb.Event_DeviceMetadataUpdatePending{}): func(t *testing.T, e, g *pb.Event, cmpInterface string) { //nolint:unparam + getTypeName(&pb.Event_DeviceMetadataUpdatePending{}): func(t *testing.T, e, g *pb.Event, _ string) { CmpDeviceMetadataUpdatePending(t, e.GetDeviceMetadataUpdatePending(), g.GetDeviceMetadataUpdatePending()) }, - getTypeName(&pb.Event_DeviceMetadataUpdated{}): func(t *testing.T, e, g *pb.Event, cmpInterface string) { //nolint:unparam + getTypeName(&pb.Event_DeviceMetadataUpdated{}): func(t *testing.T, e, g *pb.Event, _ string) { CmpDeviceMetadataUpdated(t, e.GetDeviceMetadataUpdated(), g.GetDeviceMetadataUpdated()) }, } @@ -319,7 +320,7 @@ func CmpEvent(t *testing.T, expected, got *pb.Event, cmpInterface string) { require.Equal(t, GetEventType(expected), GetEventType(got)) cmp, ok := compareEventFn[GetEventType(expected)] if !ok { - cmp = func(t *testing.T, e, g *pb.Event, cmpInterface string) { + cmp = func(t *testing.T, e, g *pb.Event, _ string) { CleanUpEvent(t, e) CleanUpEvent(t, g) test.CheckProtobufs(t, e, g, test.RequireToCheckFunc(require.Equal)) @@ -329,6 +330,26 @@ func CmpEvent(t *testing.T, expected, got *pb.Event, cmpInterface string) { cmp(t, expected, got, cmpInterface) } +func AssertCmpEvents(t *testing.T, expected, got []*pb.Event) { + assert.Len(t, got, len(expected)) + + // normalize + for i := range expected { + expected[i].SubscriptionId = "" + got[i].SubscriptionId = "" + CleanUpEvent(t, expected[i]) + CleanUpEvent(t, got[i]) + } + + // compare + for _, gotV := range got { + test.CheckProtobufs(t, expected, gotV, test.AssertToCheckFunc(assert.Contains)) + } + for _, expectedV := range expected { + test.CheckProtobufs(t, got, expectedV, test.AssertToCheckFunc(assert.Contains)) + } +} + func CmpEvents(t *testing.T, expected, got []*pb.Event) { require.Len(t, got, len(expected)) diff --git a/test/pb/pendingCommand.go b/test/pb/pendingCommand.go index bbaa9cc58..54d5f9753 100644 --- a/test/pb/pendingCommand.go +++ b/test/pb/pendingCommand.go @@ -93,7 +93,7 @@ func InitPendingEvents(ctx context.Context, t *testing.T) (pb.GrpcGatewayClient, token := oauthTest.GetDefaultAccessToken(t) ctx = kitNetGrpc.CtxWithToken(ctx, token) - conn, err := grpc.Dial(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -108,9 +108,9 @@ func InitPendingEvents(ctx context.Context, t *testing.T) (pb.GrpcGatewayClient, secureGWShutdown() createFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + createCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.CreateResource(ctx, &pb.CreateResourceRequest{ + _, errC := c.CreateResource(createCtx, &pb.CreateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -119,22 +119,22 @@ func InitPendingEvents(ctx context.Context, t *testing.T) (pb.GrpcGatewayClient, }), }, }) - require.Error(t, err) + require.Error(t, errC) } createFn() retrieveFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + retrieveCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.GetResourceFromDevice(ctx, &pb.GetResourceFromDeviceRequest{ + _, errG := c.GetResourceFromDevice(retrieveCtx, &pb.GetResourceFromDeviceRequest{ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), }) - require.Error(t, err) + require.Error(t, errG) } retrieveFn() updateFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateResource(ctx, &pb.UpdateResourceRequest{ + _, errU := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), Content: &pb.Content{ ContentType: message.AppOcfCbor.String(), @@ -143,26 +143,26 @@ func InitPendingEvents(ctx context.Context, t *testing.T) (pb.GrpcGatewayClient, }), }, }) - require.Error(t, err) + require.Error(t, errU) } updateFn() deleteFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + deleteCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.DeleteResource(ctx, &pb.DeleteResourceRequest{ + _, errD := c.DeleteResource(deleteCtx, &pb.DeleteResourceRequest{ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")), }) - require.Error(t, err) + require.Error(t, errD) } deleteFn() updateDeviceMetadataFn := func() { - ctx, cancel := context.WithTimeout(ctx, time.Second) + updateCtx, cancel := context.WithTimeout(ctx, time.Second) defer cancel() - _, err := c.UpdateDeviceMetadata(ctx, &pb.UpdateDeviceMetadataRequest{ + _, errU := c.UpdateDeviceMetadata(updateCtx, &pb.UpdateDeviceMetadataRequest{ DeviceId: deviceID, TwinEnabled: false, }) - require.Error(t, err) + require.Error(t, errU) } updateDeviceMetadataFn() updateDeviceMetadataFn() @@ -243,9 +243,9 @@ func CmpPendingCmds(t *testing.T, want []*pb.PendingCommand, got []*pb.PendingCo } func CmpCancelPendingCmdResponses(t *testing.T, want *pb.CancelPendingCommandsResponse, got *pb.CancelPendingCommandsResponse) { - sort.Strings(want.CorrelationIds) - sort.Strings(got.CorrelationIds) - require.Equal(t, want.CorrelationIds, got.CorrelationIds) + sort.Strings(want.GetCorrelationIds()) + sort.Strings(got.GetCorrelationIds()) + require.Equal(t, want.GetCorrelationIds(), got.GetCorrelationIds()) } func CleanUpResourceCreatePending(e *events.ResourceCreatePending, resetCorrelationID bool) *events.ResourceCreatePending { @@ -273,7 +273,7 @@ func CmpResourceCreatePending(t *testing.T, expected, got *events.ResourceCreate test.CheckProtobufs(t, expected, got, test.RequireToCheckFunc(require.Equal)) } -func MakeResourceCreatePending(t *testing.T, deviceID, href, correlationID string, data interface{}) *events.ResourceCreatePending { +func MakeResourceCreatePending(t *testing.T, deviceID, href string, resourceTypes []string, correlationID string, data interface{}) *events.ResourceCreatePending { return &events.ResourceCreatePending{ ResourceId: &commands.ResourceId{ DeviceId: deviceID, @@ -284,7 +284,8 @@ func MakeResourceCreatePending(t *testing.T, deviceID, href, correlationID strin CoapContentFormat: -1, Data: test.EncodeToCbor(t, data), }, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, correlationID, oauthService.DeviceUserID), + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, correlationID, oauthService.DeviceUserID), + ResourceTypes: resourceTypes, } } @@ -313,7 +314,7 @@ func CmpResourceUpdatePending(t *testing.T, expected, got *events.ResourceUpdate test.CheckProtobufs(t, expected, got, test.RequireToCheckFunc(require.Equal)) } -func MakeResourceUpdatePending(t *testing.T, deviceID, href, correlationID string, data interface{}) *events.ResourceUpdatePending { +func MakeResourceUpdatePending(t *testing.T, deviceID, href string, resourceTypes []string, correlationID string, data interface{}) *events.ResourceUpdatePending { return &events.ResourceUpdatePending{ ResourceId: &commands.ResourceId{ DeviceId: deviceID, @@ -324,7 +325,8 @@ func MakeResourceUpdatePending(t *testing.T, deviceID, href, correlationID strin CoapContentFormat: -1, Data: test.EncodeToCbor(t, data), }, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, correlationID, oauthService.DeviceUserID), + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, correlationID, oauthService.DeviceUserID), + ResourceTypes: resourceTypes, } } @@ -346,13 +348,14 @@ func CmpResourceRetrievePending(t *testing.T, expected, got *events.ResourceRetr test.CheckProtobufs(t, expected, got, test.RequireToCheckFunc(require.Equal)) } -func MakeResourceRetrievePending(deviceID, href, correlationID string) *events.ResourceRetrievePending { +func MakeResourceRetrievePending(deviceID, href string, resourceTypes []string, correlationID string) *events.ResourceRetrievePending { return &events.ResourceRetrievePending{ ResourceId: &commands.ResourceId{ DeviceId: deviceID, Href: href, }, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, correlationID, oauthService.DeviceUserID), + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, correlationID, oauthService.DeviceUserID), + ResourceTypes: resourceTypes, } } @@ -374,10 +377,11 @@ func CmpResourceDeletePending(t *testing.T, expected, got *events.ResourceDelete test.CheckProtobufs(t, expected, got, test.RequireToCheckFunc(require.Equal)) } -func MakeResourceDeletePending(deviceID, href, correlationID string) *events.ResourceDeletePending { +func MakeResourceDeletePending(deviceID, href string, resourceTypes []string, correlationID string) *events.ResourceDeletePending { return &events.ResourceDeletePending{ - ResourceId: &commands.ResourceId{DeviceId: deviceID, Href: href}, - AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, correlationID, oauthService.DeviceUserID), + ResourceId: &commands.ResourceId{DeviceId: deviceID, Href: href}, + AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, correlationID, oauthService.DeviceUserID), + ResourceTypes: resourceTypes, } } diff --git a/test/pb/resource.go b/test/pb/resource.go index de5b1b4d3..da32f6f4f 100644 --- a/test/pb/resource.go +++ b/test/pb/resource.go @@ -54,7 +54,7 @@ func MakeCreateSwitchResourceResponseData(id string) map[string]interface{} { } } -func MakeResourceCreated(t *testing.T, deviceID, href, correlationID string, data map[string]interface{}) *events.ResourceCreated { +func MakeResourceCreated(t *testing.T, deviceID, href string, resourceTypes []string, correlationID string, data map[string]interface{}) *events.ResourceCreated { return &events.ResourceCreated{ ResourceId: commands.NewResourceID(deviceID, href), Status: commands.Status_CREATED, @@ -68,7 +68,8 @@ func MakeResourceCreated(t *testing.T, deviceID, href, correlationID string, dat return test.EncodeToCbor(t, data) }(), }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, correlationID, service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, correlationID, service.DeviceUserID), + ResourceTypes: resourceTypes, } } @@ -180,26 +181,28 @@ func makeCborContent(t *testing.T, data interface{}) *commands.Content { } } -func MakeResourceChanged(t *testing.T, deviceID, href, correlationID string, data interface{}) *events.ResourceChanged { +func MakeResourceChanged(t *testing.T, deviceID, href string, resourceTypes []string, correlationID string, data interface{}) *events.ResourceChanged { return &events.ResourceChanged{ ResourceId: &commands.ResourceId{ DeviceId: deviceID, Href: href, }, - Status: commands.Status_OK, - Content: makeCborContent(t, data), - AuditContext: commands.NewAuditContext(service.DeviceUserID, correlationID, service.DeviceUserID), + Status: commands.Status_OK, + Content: makeCborContent(t, data), + AuditContext: commands.NewAuditContext(service.DeviceUserID, correlationID, service.DeviceUserID), + ResourceTypes: resourceTypes, } } -func MakeResourceDeleted(deviceID, href, correlationID string) *events.ResourceDeleted { +func MakeResourceDeleted(deviceID, href string, resourceTypes []string, correlationID string) *events.ResourceDeleted { return &events.ResourceDeleted{ ResourceId: commands.NewResourceID(deviceID, href), Status: commands.Status_OK, Content: &commands.Content{ CoapContentFormat: int32(-1), }, - AuditContext: commands.NewAuditContext(service.DeviceUserID, correlationID, service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, correlationID, service.DeviceUserID), + ResourceTypes: resourceTypes, } } @@ -262,15 +265,16 @@ func CmpResourceDeleted(t *testing.T, expected, got *events.ResourceDeleted) { test.CheckProtobufs(t, expected, got, test.RequireToCheckFunc(require.Equal)) } -func MakeResourceRetrieved(t *testing.T, deviceID, href, correlationID string, data interface{}) *events.ResourceRetrieved { +func MakeResourceRetrieved(t *testing.T, deviceID, href string, resourceTypes []string, correlationID string, data interface{}) *events.ResourceRetrieved { return &events.ResourceRetrieved{ ResourceId: &commands.ResourceId{ DeviceId: deviceID, Href: href, }, - Status: commands.Status_OK, - Content: makeCborContent(t, data), - AuditContext: commands.NewAuditContext(service.DeviceUserID, correlationID, service.DeviceUserID), + Status: commands.Status_OK, + Content: makeCborContent(t, data), + AuditContext: commands.NewAuditContext(service.DeviceUserID, correlationID, service.DeviceUserID), + ResourceTypes: resourceTypes, } } @@ -294,7 +298,7 @@ func CmpResourceRetrieved(t *testing.T, expected, got *events.ResourceRetrieved) test.CheckProtobufs(t, expected, got, test.RequireToCheckFunc(require.Equal)) } -func MakeResourceUpdated(t *testing.T, deviceID, href, correlationID string, data interface{}) *events.ResourceUpdated { +func MakeResourceUpdated(t *testing.T, deviceID, href string, resourceTypes []string, correlationID string, data interface{}) *events.ResourceUpdated { return &events.ResourceUpdated{ ResourceId: &commands.ResourceId{ DeviceId: deviceID, @@ -309,7 +313,8 @@ func MakeResourceUpdated(t *testing.T, deviceID, href, correlationID string, dat } return makeCborContent(t, data) }(), - AuditContext: commands.NewAuditContext(service.DeviceUserID, correlationID, service.DeviceUserID), + AuditContext: commands.NewAuditContext(service.DeviceUserID, correlationID, service.DeviceUserID), + ResourceTypes: resourceTypes, } } @@ -412,9 +417,9 @@ func CmpResourceValuesBasic(t *testing.T, expected, got []*pb.Resource) { } func CmpHubConfigurationResponse(t *testing.T, expected, got *pb.HubConfigurationResponse) { - require.NotEmpty(t, got.CertificateAuthorities) + require.NotEmpty(t, got.GetCertificateAuthorities()) got.CertificateAuthorities = "" - require.NotEqual(t, int64(0), got.CurrentTime) + require.NotEqual(t, int64(0), got.GetCurrentTime()) got.CurrentTime = 0 test.CheckProtobufs(t, expected, got, test.RequireToCheckFunc(require.Equal)) } diff --git a/test/pb/snapshot.go b/test/pb/snapshot.go index a8fa34d77..bf9c22aa0 100644 --- a/test/pb/snapshot.go +++ b/test/pb/snapshot.go @@ -15,7 +15,7 @@ func CleanUpResourceStateSnapshotTaken(e *events.ResourceStateSnapshotTaken, res if e.GetAuditContext() != nil && resetCorrelationID { e.GetAuditContext().CorrelationId = "" } - CleanUpResourceChanged(e.LatestResourceChange, resetCorrelationID) + CleanUpResourceChanged(e.GetLatestResourceChange(), resetCorrelationID) if e.GetLatestResourceChange().GetContent().GetData() != nil { e.LatestResourceChange.Content.Data = nil } diff --git a/test/sdkclient.go b/test/sdk/client.go similarity index 91% rename from test/sdkclient.go rename to test/sdk/client.go index 9343e9c4d..598511952 100644 --- a/test/sdkclient.go +++ b/test/sdk/client.go @@ -1,4 +1,4 @@ -package test +package sdk import ( "context" @@ -6,6 +6,7 @@ import ( "crypto/tls" "crypto/x509" "encoding/pem" + "errors" "fmt" "os" "time" @@ -22,7 +23,7 @@ type testSetupSecureClient struct { mfgCert tls.Certificate } -var errNotSet = fmt.Errorf("not set") +var errNotSet = errors.New("not set") func (c *testSetupSecureClient) GetManufacturerCertificate() (tls.Certificate, error) { if c.mfgCert.PrivateKey == nil { @@ -55,6 +56,8 @@ type sdkConfig struct { // TODO: replace by notBefore and notAfter validFrom string // RFC3339, or relative time such as now-1m validFor string // string parsable by time.ParseDuration + + useDeviceIDInQuery bool } // Option interface used for setting optional sdkConfig properties. @@ -92,6 +95,12 @@ func WithValidity(validFrom, validFor string) Option { }) } +func WithUseDeviceIDInQuery(useDeviceIDInQuery bool) Option { + return optionFunc(func(cfg *sdkConfig) { + cfg.useDeviceIDInQuery = useDeviceIDInQuery + }) +} + func getSDKConfig(opts ...Option) (*sdkConfig, error) { c := &sdkConfig{ id: CertIdentity, @@ -116,7 +125,7 @@ func getSDKConfig(opts ...Option) (*sdkConfig, error) { return c, nil } -func NewSDKClient(opts ...Option) (*client.Client, error) { +func NewClient(opts ...Option) (*client.Client, error) { c, err := getSDKConfig(opts...) if err != nil { return nil, err @@ -124,7 +133,7 @@ func NewSDKClient(opts ...Option) (*client.Client, error) { mfgTrustedCABlock, _ := pem.Decode(MfgTrustedCA) if mfgTrustedCABlock == nil { - return nil, fmt.Errorf("mfgTrustedCABlock is empty") + return nil, errors.New("mfgTrustedCABlock is empty") } mfgCA, err := x509.ParseCertificates(mfgTrustedCABlock.Bytes) if err != nil { @@ -137,16 +146,16 @@ func NewSDKClient(opts ...Option) (*client.Client, error) { identityIntermediateCABlock, _ := pem.Decode(identityIntermediateCA) if identityIntermediateCABlock == nil { - return nil, fmt.Errorf("identityIntermediateCABlock is empty") + return nil, errors.New("identityIntermediateCABlock is empty") } identityIntermediateCAKeyBlock, _ := pem.Decode(identityIntermediateCAKey) if identityIntermediateCAKeyBlock == nil { - return nil, fmt.Errorf("identityIntermediateCAKeyBlock is empty") + return nil, errors.New("identityIntermediateCAKeyBlock is empty") } identityTrustedCABlock, _ := pem.Decode(identityTrustedCA) if identityTrustedCABlock == nil { - return nil, fmt.Errorf("identityTrustedCABlock is empty") + return nil, errors.New("identityTrustedCABlock is empty") } identityTrustedCACert, err := x509.ParseCertificates(identityTrustedCABlock.Bytes) if err != nil { @@ -172,6 +181,7 @@ func NewSDKClient(opts ...Option) (*client.Client, error) { cfg := client.Config{ DisablePeerTCPSignalMessageCSMs: true, DeviceOwnershipSDK: devCfg, + UseDeviceIDInQuery: c.useDeviceIDInQuery, } client, err := client.NewClientFromConfig(&cfg, &testSetupSecureClient{ diff --git a/test/security/jwk.go b/test/security/jwk.go index d90d2563c..f373d487b 100644 --- a/test/security/jwk.go +++ b/test/security/jwk.go @@ -70,7 +70,7 @@ func NewTestJwks(t *testing.T) JWKServer { require.NoError(t, err) mux := http.NewServeMux() - mux.HandleFunc(jwksUri, func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc(jwksUri, func(w http.ResponseWriter, _ *http.Request) { if _, err := io.WriteString(w, string(jwks)); err != nil { log.Debugf("failed to write jwks: %v", err) } diff --git a/test/test.go b/test/test.go index 83b370bb5..605679d74 100644 --- a/test/test.go +++ b/test/test.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "log" "net" "os" "os/exec" @@ -15,12 +14,14 @@ import ( deviceClient "github.com/plgd-dev/device/v2/client" "github.com/plgd-dev/device/v2/client/core" + bridgeDevice "github.com/plgd-dev/device/v2/cmd/bridge-device/device" + deviceCoap "github.com/plgd-dev/device/v2/pkg/net/coap" "github.com/plgd-dev/device/v2/schema" "github.com/plgd-dev/device/v2/schema/acl" "github.com/plgd-dev/device/v2/schema/cloud" "github.com/plgd-dev/device/v2/schema/collection" "github.com/plgd-dev/device/v2/schema/configuration" - "github.com/plgd-dev/device/v2/schema/device" + schemaDevice "github.com/plgd-dev/device/v2/schema/device" "github.com/plgd-dev/device/v2/schema/interfaces" "github.com/plgd-dev/device/v2/schema/maintenance" "github.com/plgd-dev/device/v2/schema/platform" @@ -37,16 +38,20 @@ import ( "github.com/plgd-dev/hub/v2/resource-aggregate/commands" "github.com/plgd-dev/hub/v2/resource-aggregate/events" "github.com/plgd-dev/hub/v2/test/config" + "github.com/plgd-dev/hub/v2/test/device" + "github.com/plgd-dev/hub/v2/test/device/bridge" + "github.com/plgd-dev/hub/v2/test/device/ocf" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" + "github.com/plgd-dev/hub/v2/test/sdk" "github.com/plgd-dev/kit/v2/codec/json" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ugorji/go/codec" - "go.uber.org/atomic" ) type ResourceLinkRepresentation struct { Href string /*`json:"href"`*/ + ResourceTypes []string /*`json:"rt"`*/ Representation interface{} /*`json:"rep"`*/ } @@ -59,57 +64,85 @@ func (d *ResourceLinkRepresentation) MarshalJSON() ([]byte, error) { } func (d *ResourceLinkRepresentation) UnmarshalJSON(data []byte) error { - reps := map[string]func(data []byte) (interface{}, error){ - configuration.ResourceURI: func(data []byte) (interface{}, error) { - var r configuration.Configuration - err := json.Decode(data, &r) - return r, err - }, - device.ResourceURI: func(data []byte) (interface{}, error) { - var r device.Device - err := json.Decode(data, &r) - r.ProtocolIndependentID = "" - return r, err - }, - platform.ResourceURI: func(data []byte) (interface{}, error) { - var r platform.Platform - err := json.Decode(data, &r) - r.PlatformIdentifier = "" - return r, err - }, - maintenance.ResourceURI: func(data []byte) (interface{}, error) { - var r MaintenanceResourceRepresentation - err := json.Decode(data, &r) - return r, err + type representation struct { + decode func(data []byte) (interface{}, error) + resourceTypes []string + } + reps := map[string]representation{ + configuration.ResourceURI: { + decode: func(data []byte) (interface{}, error) { + var r configuration.Configuration + err := json.Decode(data, &r) + return r, err + }, + resourceTypes: []string{configuration.ResourceType}, + }, + schemaDevice.ResourceURI: { + decode: func(data []byte) (interface{}, error) { + var r schemaDevice.Device + err := json.Decode(data, &r) + r.ProtocolIndependentID = "" + return r, err + }, + resourceTypes: TestResourceDeviceResourceTypes, + }, + platform.ResourceURI: { + decode: func(data []byte) (interface{}, error) { + var r platform.Platform + err := json.Decode(data, &r) + r.PlatformIdentifier = "" + return r, err + }, + resourceTypes: []string{platform.ResourceType}, }, - plgdtime.ResourceURI: func(data []byte) (interface{}, error) { - var r PlgdTimeResourceRepresentation - err := json.Decode(data, &r) - return r, err + maintenance.ResourceURI: { + decode: func(data []byte) (interface{}, error) { + var r MaintenanceResourceRepresentation + err := json.Decode(data, &r) + return r, err + }, + resourceTypes: []string{maintenance.ResourceType}, }, - TestResourceLightInstanceHref("1"): func(data []byte) (interface{}, error) { - var r LightResourceRepresentation - err := json.Decode(data, &r) - return r, err + plgdtime.ResourceURI: { + decode: func(data []byte) (interface{}, error) { + var r PlgdTimeResourceRepresentation + err := json.Decode(data, &r) + return r, err + }, + resourceTypes: []string{plgdtime.ResourceType}, }, - TestResourceSwitchesHref: func(data []byte) (interface{}, error) { - var r schema.ResourceLinks - err := json.Decode(data, &r) - if err != nil { - return nil, err - } - r.Sort() - for i := range r { - r[i].Endpoints = nil - r[i].InstanceID = 0 - } - - return r, err + TestResourceLightInstanceHref("1"): { + decode: func(data []byte) (interface{}, error) { + var r LightResourceRepresentation + err := json.Decode(data, &r) + return r, err + }, + resourceTypes: TestResourceLightInstanceResourceTypes, + }, + TestResourceSwitchesHref: { + decode: func(data []byte) (interface{}, error) { + var r schema.ResourceLinks + err := json.Decode(data, &r) + if err != nil { + return nil, err + } + r.Sort() + for i := range r { + r[i].Endpoints = nil + r[i].InstanceID = 0 + } + + return r, err + }, + resourceTypes: TestResourceSwitchesResourceTypes, }, - TestResourceSwitchesInstanceHref("1"): func(data []byte) (interface{}, error) { - var r SwitchResourceRepresentation - err := json.Decode(data, &r) - return r, err + TestResourceSwitchesInstanceHref("1"): { + decode: func(data []byte) (interface{}, error) { + var r SwitchResourceRepresentation + err := json.Decode(data, &r) + return r, err + }, + resourceTypes: TestResourceLightInstanceResourceTypes, }, } var rep struct { @@ -120,10 +153,12 @@ func (d *ResourceLinkRepresentation) UnmarshalJSON(data []byte) error { if err != nil { return err } - dec := func(data []byte) (interface{}, error) { - var r interface{} - err := json.Decode(data, &r) - return r, err + dec := representation{ + decode: func(data []byte) (interface{}, error) { + var r interface{} + errD := json.Decode(data, &r) + return r, errD + }, } for k, v := range reps { if strings.HasSuffix(rep.Href, k) { @@ -132,7 +167,8 @@ func (d *ResourceLinkRepresentation) UnmarshalJSON(data []byte) error { } } d.Href = rep.Href - d.Representation, err = dec(rep.Rep) + d.ResourceTypes = dec.resourceTypes + d.Representation, err = dec.decode(rep.Rep) if err != nil { return err } @@ -144,9 +180,12 @@ var ( TestDeviceNameWithOicResObservable string TestDeviceModelNumber = "CS-0" TestDeviceSoftwareVersion = "1.0.1-rc1" + TestDeviceType device.Type - TestDevsimResources []schema.ResourceLink - TestDevsimBackendResources []schema.ResourceLink + TestResourceSwitchesInstanceResourceTypes = []string{types.BINARY_SWITCH} + TestResourceSwitchesResourceTypes = []string{collection.ResourceType} + TestResourceLightInstanceResourceTypes = []string{types.CORE_LIGHT} + TestResourceDeviceResourceTypes = []string{types.DEVICE_CLOUD, schemaDevice.ResourceType} testIovityLiteVersion *sync.Map[string, uint32] ) @@ -163,6 +202,10 @@ func TestResourceSwitchesInstanceHref(id string) string { return TestResourceSwitchesHref + "/" + id } +func TestBridgeDeviceInstanceName(id string) string { + return "bridged-device-" + id +} + type LightResourceRepresentation struct { Name string `json:"name"` Power uint64 `json:"power"` @@ -190,93 +233,27 @@ type CollectionLinkRepresentation struct { type CollectionLinkRepresentations []CollectionLinkRepresentation func init() { - TestDeviceName = "devsim-" + MustGetHostname() + if name := os.Getenv("TEST_DEVICE_NAME"); name != "" { + TestDeviceName = name + } else { + TestDeviceName = "devsim-" + MustGetHostname() + } TestDeviceNameWithOicResObservable = "devsim-resobs-" + MustGetHostname() - - // when adding new resource, add also representation to GetAllBackendResourceRepresentations func - TestDevsimResources = []schema.ResourceLink{ - { - Href: platform.ResourceURI, - ResourceTypes: []string{platform.ResourceType}, - Interfaces: []string{interfaces.OC_IF_R, interfaces.OC_IF_BASELINE}, - Policy: &schema.Policy{ - BitMask: 3, - }, - }, - - { - Href: device.ResourceURI, - ResourceTypes: []string{types.DEVICE_CLOUD, device.ResourceType}, - Interfaces: []string{interfaces.OC_IF_R, interfaces.OC_IF_BASELINE}, - Policy: &schema.Policy{ - BitMask: 3, - }, - }, - - { - Href: configuration.ResourceURI, - ResourceTypes: []string{configuration.ResourceType}, - Interfaces: []string{interfaces.OC_IF_RW, interfaces.OC_IF_BASELINE}, - Policy: &schema.Policy{ - BitMask: 3, - }, - }, - - { - Href: TestResourceLightInstanceHref("1"), - ResourceTypes: []string{types.CORE_LIGHT}, - Interfaces: []string{interfaces.OC_IF_RW, interfaces.OC_IF_BASELINE}, - Policy: &schema.Policy{ - BitMask: 3, - }, - }, - - { - Href: TestResourceSwitchesHref, - ResourceTypes: []string{collection.ResourceType}, - Interfaces: []string{interfaces.OC_IF_LL, interfaces.OC_IF_CREATE, interfaces.OC_IF_B, interfaces.OC_IF_BASELINE}, - Policy: &schema.Policy{ - BitMask: 3, - }, - }, - - { - Href: maintenance.ResourceURI, - ResourceTypes: []string{maintenance.ResourceType}, - Interfaces: []string{interfaces.OC_IF_RW, interfaces.OC_IF_BASELINE}, - Policy: &schema.Policy{ - BitMask: 1, - }, - }, - - { - Href: plgdtime.ResourceURI, - ResourceTypes: []string{plgdtime.ResourceType}, - Interfaces: []string{interfaces.OC_IF_RW, interfaces.OC_IF_BASELINE}, - Policy: &schema.Policy{ - BitMask: 3, - }, - }, - - { - Href: softwareupdate.ResourceURI, - ResourceTypes: []string{softwareupdate.ResourceType}, - Interfaces: []string{interfaces.OC_IF_RW, interfaces.OC_IF_BASELINE}, - Policy: &schema.Policy{ - BitMask: 3, - }, - }, + if dtype := os.Getenv("TEST_DEVICE_TYPE"); dtype == "bridged" { + TestDeviceType = device.Bridged + } else { + TestDeviceType = device.OCF } testIovityLiteVersion = sync.NewMap[string, uint32]() } -func GetDeviceResourceRepresentation(deviceID, deviceName string) device.Device { - return device.Device{ +func GetDeviceResourceRepresentation(deviceID, deviceName string) schemaDevice.Device { + return schemaDevice.Device{ ID: deviceID, Interfaces: []string{interfaces.OC_IF_R, interfaces.OC_IF_BASELINE}, Name: deviceName, - ResourceTypes: []string{types.DEVICE_CLOUD, device.ResourceType}, + ResourceTypes: TestResourceDeviceResourceTypes, DataModelVersion: "ocf.res.1.3.0", SpecificationVersion: "ocf.2.0.5", ModelNumber: TestDeviceModelNumber, @@ -306,20 +283,24 @@ func GetAllBackendResourceRepresentations(t *testing.T, deviceID, deviceName str Power: 0, State: false, }, + ResourceTypes: TestResourceLightInstanceResourceTypes, }, { Href: "/" + commands.NewResourceID(deviceID, configuration.ResourceURI).ToString(), Representation: configuration.Configuration{ Name: deviceName, }, + ResourceTypes: []string{configuration.ResourceType}, }, { - Href: "/" + commands.NewResourceID(deviceID, device.ResourceURI).ToString(), + Href: "/" + commands.NewResourceID(deviceID, schemaDevice.ResourceURI).ToString(), Representation: dev, + ResourceTypes: TestResourceDeviceResourceTypes, }, { Href: "/" + commands.NewResourceID(deviceID, maintenance.ResourceURI).ToString(), Representation: MaintenanceResourceRepresentation{}, + ResourceTypes: []string{maintenance.ResourceType}, }, { Href: "/" + commands.NewResourceID(deviceID, platform.ResourceURI).ToString(), @@ -327,14 +308,17 @@ func GetAllBackendResourceRepresentations(t *testing.T, deviceID, deviceName str ManufacturerName: "ocfcloud.com", Version: iotVersion, }, + ResourceTypes: []string{platform.ResourceType}, }, { Href: "/" + commands.NewResourceID(deviceID, TestResourceSwitchesHref).ToString(), Representation: schema.ResourceLinks{}, + ResourceTypes: []string{collection.ResourceType}, }, { Href: "/" + commands.NewResourceID(deviceID, plgdtime.ResourceURI).ToString(), Representation: PlgdTimeResourceRepresentation{}, + ResourceTypes: []string{plgdtime.ResourceType}, }, { Href: "/" + commands.NewResourceID(deviceID, softwareupdate.ResourceURI).ToString(), @@ -347,6 +331,7 @@ func GetAllBackendResourceRepresentations(t *testing.T, deviceID, deviceName str "swupdateresult": uint64(0), "updatetime": "1970-01-01T00:00:00Z", }, + ResourceTypes: []string{softwareupdate.ResourceType}, }, } } @@ -365,7 +350,7 @@ func DefaultSwitchResourceLink(deviceID, id string) schema.ResourceLink { return schema.ResourceLink{ DeviceID: deviceID, Href: TestResourceSwitchesInstanceHref(id), - ResourceTypes: []string{types.BINARY_SWITCH}, + ResourceTypes: TestResourceSwitchesInstanceResourceTypes, Interfaces: []string{interfaces.OC_IF_A, interfaces.OC_IF_BASELINE}, Policy: &schema.Policy{ BitMask: schema.Discoverable | schema.Observable, @@ -461,25 +446,32 @@ func AddDeviceSwitchResources(ctx context.Context, t *testing.T, deviceID string return links } -func setAccessForCloud(ctx context.Context, t *testing.T, c *deviceClient.Client, deviceID string) { - cloudSID := config.HubID() - require.NotEmpty(t, cloudSID) - +func setAccessForCloud(ctx context.Context, c *deviceClient.Client, deviceID, cloudSID string) error { d, links, err := c.GetDevice(ctx, deviceID) - require.NoError(t, err) - + if err != nil { + return err + } defer func() { - errC := d.Close(ctx) - require.NoError(t, errC) + _ = d.Close(ctx) }() + + // skip setting of ACLs for insecure devices + if !d.IsSecured() { + return nil + } + p, err := d.Provision(ctx, links) - require.NoError(t, err) + if err != nil { + return err + } defer func() { _ = p.Close(ctx) }() link, err := core.GetResourceLink(links, acl.ResourceURI) - require.NoError(t, err) + if err != nil { + return err + } confResources := acl.AllResources for _, href := range links.GetResourceHrefs(maintenance.ResourceType) { confResources = append(confResources, acl.Resource{ @@ -507,37 +499,56 @@ func setAccessForCloud(ctx context.Context, t *testing.T, c *deviceClient.Client }, } - err = p.UpdateResource(ctx, link, setAcl, nil) + return p.UpdateResource(ctx, link, setAcl, nil) +} + +func disownDevice(t *testing.T, d device.Device) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*8) + defer cancel() + client, err := sdk.NewClient(d.GetSDKClientOptions()...) + require.NoError(t, err) + defer func() { + _ = client.Close(ctx) + }() + err = client.DisownDevice(ctx, d.GetID()) require.NoError(t, err) + time.Sleep(time.Second * 2) } -func OnboardDevSimForClient(ctx context.Context, t *testing.T, c pb.GrpcGatewayClient, clientID, deviceID, hubEndpoint string, expectedResources []schema.ResourceLink) (string, func()) { +func OnboardDevice(ctx context.Context, t *testing.T, c pb.GrpcGatewayClient, d device.Device, hubEndpoint string, expectedResources []schema.ResourceLink) func() { + return OnboardDeviceForClient(ctx, t, c, d, config.OAUTH_MANAGER_CLIENT_ID, hubEndpoint, expectedResources) +} + +func OnboardDeviceForClient(ctx context.Context, t *testing.T, c pb.GrpcGatewayClient, d device.Device, clientID, hubEndpoint string, expectedResources []schema.ResourceLink) func() { cloudSID := config.HubID() require.NotEmpty(t, cloudSID) - devClient, err := NewSDKClient() + devClient, err := sdk.NewClient(d.GetSDKClientOptions()...) require.NoError(t, err) defer func() { _ = devClient.Close(ctx) }() - deviceID, err = devClient.OwnDevice(ctx, deviceID, deviceClient.WithOTM(deviceClient.OTMType_JustWorks)) + + deviceID, err := devClient.OwnDevice(ctx, d.GetID(), deviceClient.WithOTM(deviceClient.OTMType_JustWorks)) require.NoError(t, err) + d.SetID(deviceID) - setAccessForCloud(ctx, t, devClient, deviceID) + err = setAccessForCloud(ctx, devClient, d.GetID(), cloudSID) + require.NoError(t, err) - code := oauthTest.GetAuthorizationCode(t, config.OAUTH_SERVER_HOST, clientID, deviceID, "") + code := oauthTest.GetAuthorizationCode(t, config.OAUTH_SERVER_HOST, clientID, d.GetID(), "") onboard := func() { var cloudRes cloud.Configuration - err = devClient.GetResource(ctx, deviceID, cloud.ResourceURI, &cloudRes) + err = devClient.GetResource(ctx, d.GetID(), cloud.ResourceURI, &cloudRes) require.NoError(t, err) if cloudRes.ProvisioningStatus != cloud.ProvisioningStatus_UNINITIALIZED { // device cloud is configured so we need to remove it first - err = devClient.OffboardDevice(ctx, deviceID) + err = devClient.OffboardDevice(ctx, d.GetID()) require.NoError(t, err) } - err = devClient.OnboardDevice(ctx, deviceID, config.DEVICE_PROVIDER, hubEndpoint, code, cloudSID) + err = devClient.OnboardDevice(ctx, d.GetID(), config.DEVICE_PROVIDER, hubEndpoint, code, cloudSID) require.NoError(t, err) } if len(expectedResources) > 0 { @@ -553,7 +564,7 @@ func OnboardDevSimForClient(ctx context.Context, t *testing.T, c pb.GrpcGatewayC ev, err := subClient.Recv() require.NoError(t, err) expectedEvent := &pb.Event{ - SubscriptionId: ev.SubscriptionId, + SubscriptionId: ev.GetSubscriptionId(), CorrelationId: "allEvents", Type: &pb.Event_OperationProcessed_{ OperationProcessed: &pb.Event_OperationProcessed{ @@ -565,47 +576,43 @@ func OnboardDevSimForClient(ctx context.Context, t *testing.T, c pb.GrpcGatewayC } CheckProtobufs(t, expectedEvent, ev, RequireToCheckFunc(require.Equal)) onboard() - WaitForDevice(t, subClient, deviceID, ev.GetSubscriptionId(), ev.GetCorrelationId(), expectedResources) + WaitForDevice(t, subClient, d, ev.GetSubscriptionId(), ev.GetCorrelationId(), expectedResources) err = subClient.CloseSend() require.NoError(t, err) } else { onboard() } - return deviceID, func() { - DisownDevice(t, deviceID) + return func() { + disownDevice(t, d) } } +func OnboardDevSimForClient(ctx context.Context, t *testing.T, c pb.GrpcGatewayClient, clientID, deviceID, hubEndpoint string, expectedResources []schema.ResourceLink) (string, func()) { + d := ocf.NewDevice(deviceID, TestDeviceName) + cleanup := OnboardDeviceForClient(ctx, t, c, d, clientID, hubEndpoint, expectedResources) + return d.GetID(), cleanup +} + func OnboardDevSim(ctx context.Context, t *testing.T, c pb.GrpcGatewayClient, deviceID, hubEndpoint string, expectedResources []schema.ResourceLink) (string, func()) { return OnboardDevSimForClient(ctx, t, c, config.OAUTH_MANAGER_CLIENT_ID, deviceID, hubEndpoint, expectedResources) } -func OffBoardDevSim(ctx context.Context, t *testing.T, deviceID string) { - devClient, err := NewSDKClient() +func OffboardDevice(ctx context.Context, t *testing.T, d device.Device) { + devClient, err := sdk.NewClient(d.GetSDKClientOptions()...) require.NoError(t, err) defer func() { _ = devClient.Close(ctx) }() - - err = devClient.OffboardDevice(ctx, deviceID) + err = devClient.OffboardDevice(ctx, d.GetID()) require.NoError(t, err) } -func DisownDevice(t *testing.T, deviceID string) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*8) - defer cancel() - client, err := NewSDKClient() - require.NoError(t, err) - defer func() { - _ = client.Close(ctx) - }() - err = client.DisownDevice(ctx, deviceID) - require.NoError(t, err) - time.Sleep(time.Second * 2) +func OffBoardDevSim(ctx context.Context, t *testing.T, deviceID string) { + OffboardDevice(ctx, t, ocf.NewDevice(deviceID, TestDeviceName)) } -func WaitForDevice(t *testing.T, client pb.GrpcGateway_SubscribeToEventsClient, deviceID, subID, correlationID string, expectedResources []schema.ResourceLink) { +func WaitForDevice(t *testing.T, client pb.GrpcGateway_SubscribeToEventsClient, dev device.Device, subID, correlationID string, expectedResources []schema.ResourceLink) { getID := func(ev *pb.Event) string { switch v := ev.GetType().(type) { case *pb.Event_DeviceRegistered_: @@ -637,6 +644,11 @@ func WaitForDevice(t *testing.T, client pb.GrpcGateway_SubscribeToEventsClient, val.DeviceMetadataUpdated.GetConnection().ConnectedAt = 0 require.NotEmpty(t, val.DeviceMetadataUpdated.GetConnection().GetServiceId()) val.DeviceMetadataUpdated.GetConnection().ServiceId = "" + if dev.GetType() != device.Bridged && !config.COAP_GATEWAY_UDP_ENABLED { + // TODO: fix bug in iotivity-lite, for DTLS it is not fill endpoints + require.NotEmpty(t, val.DeviceMetadataUpdated.GetConnection().GetLocalEndpoints()) + } + val.DeviceMetadataUpdated.GetConnection().LocalEndpoints = nil } if val.DeviceMetadataUpdated.GetTwinSynchronization() != nil { val.DeviceMetadataUpdated.GetTwinSynchronization().CommandMetadata = nil @@ -669,7 +681,7 @@ func WaitForDevice(t *testing.T, client pb.GrpcGateway_SubscribeToEventsClient, CorrelationId: correlationID, Type: &pb.Event_DeviceRegistered_{ DeviceRegistered: &pb.Event_DeviceRegistered{ - DeviceIds: []string{deviceID}, + DeviceIds: []string{dev.GetID()}, EventMetadata: &isEvents.EventMetadata{ HubId: config.HubID(), }, @@ -689,7 +701,7 @@ func WaitForDevice(t *testing.T, client pb.GrpcGateway_SubscribeToEventsClient, CorrelationId: correlationID, Type: &pb.Event_DeviceMetadataUpdated{ DeviceMetadataUpdated: &events.DeviceMetadataUpdated{ - DeviceId: deviceID, + DeviceId: dev.GetID(), Connection: &commands.Connection{ Status: commands.Connection_ONLINE, Protocol: StringToApplicationProtocol(config.ACTIVE_COAP_SCHEME), @@ -717,7 +729,7 @@ func WaitForDevice(t *testing.T, client pb.GrpcGateway_SubscribeToEventsClient, CorrelationId: correlationID, Type: &pb.Event_DeviceMetadataUpdated{ DeviceMetadataUpdated: &events.DeviceMetadataUpdated{ - DeviceId: deviceID, + DeviceId: dev.GetID(), Connection: &commands.Connection{ Status: commands.Connection_ONLINE, Protocol: StringToApplicationProtocol(config.ACTIVE_COAP_SCHEME), @@ -745,7 +757,7 @@ func WaitForDevice(t *testing.T, client pb.GrpcGateway_SubscribeToEventsClient, CorrelationId: correlationID, Type: &pb.Event_DeviceMetadataUpdated{ DeviceMetadataUpdated: &events.DeviceMetadataUpdated{ - DeviceId: deviceID, + DeviceId: dev.GetID(), Connection: &commands.Connection{ Status: commands.Connection_ONLINE, Protocol: StringToApplicationProtocol(config.ACTIVE_COAP_SCHEME), @@ -762,8 +774,8 @@ func WaitForDevice(t *testing.T, client pb.GrpcGateway_SubscribeToEventsClient, CorrelationId: correlationID, Type: &pb.Event_ResourcePublished{ ResourcePublished: &events.ResourceLinksPublished{ - DeviceId: deviceID, - Resources: ResourceLinksToResources(deviceID, expectedResources), + DeviceId: dev.GetID(), + Resources: ResourceLinksToResources(dev.GetID(), expectedResources), }, }, }, @@ -771,15 +783,16 @@ func WaitForDevice(t *testing.T, client pb.GrpcGateway_SubscribeToEventsClient, for _, r := range expectedResources { expectedEvents[getID(&pb.Event{Type: &pb.Event_ResourceChanged{ ResourceChanged: &events.ResourceChanged{ - ResourceId: commands.NewResourceID(deviceID, r.Href), + ResourceId: commands.NewResourceID(dev.GetID(), r.Href), }, }})] = &pb.Event{ SubscriptionId: subID, CorrelationId: correlationID, Type: &pb.Event_ResourceChanged{ ResourceChanged: &events.ResourceChanged{ - ResourceId: commands.NewResourceID(deviceID, r.Href), - Status: commands.Status_OK, + ResourceId: commands.NewResourceID(dev.GetID(), r.Href), + Status: commands.Status_OK, + ResourceTypes: r.ResourceTypes, }, }, } @@ -817,12 +830,12 @@ func MustGetHostname() string { return n } -func MustFindDeviceByName(name string) (deviceID string) { +func MustFindDeviceByName(name string, getResourceOpts ...device.GetResourceOpts) (deviceID string) { var err error for i := 0; i < 3; i++ { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() - deviceID, err = FindDeviceByName(ctx, name) + deviceID, err = device.FindDeviceByName(ctx, name, getResourceOpts...) if err == nil { return deviceID } @@ -830,70 +843,49 @@ func MustFindDeviceByName(name string) (deviceID string) { panic(err) } -type findDeviceIDByNameHandler struct { - id atomic.Value - name string - cancel context.CancelFunc -} - -func (h *findDeviceIDByNameHandler) Handle(ctx context.Context, dev *core.Device) { - defer func() { - if errC := dev.Close(ctx); errC != nil { - h.Error(errC) - } - }() - deviceLinks, err := dev.GetResourceLinks(ctx, dev.GetEndpoints()) - if err != nil { - h.Error(err) - return - } - l, ok := deviceLinks.GetResourceLink(device.ResourceURI) - if !ok { - return - } - var d device.Device - err = dev.GetResource(ctx, l, &d) - if err != nil { - h.Error(err) - return - } - if d.Name == h.name { - h.id.Store(d.ID) - h.cancel() +func GetBridgeDeviceConfig() (bridgeDevice.Config, error) { + cfgFile := os.Getenv("TEST_BRIDGE_DEVICE_CONFIG") + if cfgFile == "" { + return bridgeDevice.Config{}, errors.New("TEST_BRIDGE_DEVICE_CONFIG not set") } + return bridgeDevice.LoadConfig(cfgFile) } -func (h *findDeviceIDByNameHandler) Error(err error) { - if errors.Is(err, context.Canceled) { - return +func MustFindTestDevice() device.Device { + var getResourceOpts []device.GetResourceOpts + if TestDeviceType == device.Bridged { + getResourceOpts = append(getResourceOpts, func(d *core.Device) deviceCoap.OptionFunc { + return deviceCoap.WithQuery("di=" + d.DeviceID()) + }) } - log.Printf("find device ID by name handler error: %v", err.Error()) -} -func FindDeviceByName(ctx context.Context, name string) (deviceID string, _ error) { - client := core.NewClient() - - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - h := findDeviceIDByNameHandler{ - name: name, - cancel: cancel, + var deviceID string + var err error + for i := 0; i < 3; i++ { + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + deviceID, err = device.FindDeviceByName(ctx, TestDeviceName, getResourceOpts...) + if err == nil { + break + } } - err := client.GetDevicesByMulticast(ctx, core.DefaultDiscoveryConfiguration(), &h) if err != nil { - return "", fmt.Errorf("could not find the device named %s: %w", name, err) + panic(err) } - id, ok := h.id.Load().(string) - if !ok || id == "" { - return "", fmt.Errorf("could not find the device named %s: not found", name) + + if TestDeviceType == device.Bridged { + bridgeDeviceCfg, err := GetBridgeDeviceConfig() + if err != nil { + panic(err) + } + return bridge.NewDevice(deviceID, TestDeviceName, bridgeDeviceCfg.NumResourcesPerDevice, true) } - return id, nil + return ocf.NewDevice(deviceID, TestDeviceName) } func IsDiscoveryResourceBatchObservable(ctx context.Context, t *testing.T, deviceID string) bool { - devClient, err := NewSDKClient() + devClient, err := sdk.NewClient() require.NoError(t, err) defer func() { _ = devClient.Close(ctx) @@ -913,15 +905,16 @@ func IsDiscoveryResourceBatchObservable(ctx context.Context, t *testing.T, devic return false } -func GetResource(ctx context.Context, deviceID, resourceURI, resourceType string, resp interface{}) error { - devClient, err := NewSDKClient() +func GetResource(ctx context.Context, deviceID, resourceURI, resourceType string, resp interface{}, opts ...deviceClient.GetOption) error { + devClient, err := sdk.NewClient() defer func() { _ = devClient.Close(ctx) }() if err != nil { return err } - err = devClient.GetResource(ctx, deviceID, resourceURI, resp, deviceClient.WithResourceTypes(resourceType)) + opts = append(opts, deviceClient.WithResourceTypes(resourceType)) + err = devClient.GetResource(ctx, deviceID, resourceURI, resp, opts...) if err != nil { return err } @@ -944,15 +937,15 @@ func GetIotivityLiteVersion(t *testing.T, deviceID string) uint32 { func DeviceIsBatchObservable(ctx context.Context, t *testing.T, deviceID string) bool { var links schema.ResourceLinks - err := GetResource(ctx, deviceID, resources.ResourceURI, resources.ResourceType, &links) + err := GetResource(ctx, deviceID, resources.ResourceURI, resources.ResourceType, &links, deviceClient.WithQuery("di="+deviceID)) require.NoError(t, err) - require.Equal(t, 1, len(links)) + require.Len(t, links, 1) return links[0].Policy.BitMask.Has(schema.Observable) && pkgStrings.Contains(links[0].Interfaces, interfaces.OC_IF_B) } func GetAllBackendResourceLinks() schema.ResourceLinks { - return append(TestDevsimResources, TestDevsimBackendResources...) + return ocf.TestResources } func ProtobufToInterface(t *testing.T, val interface{}) interface{} { @@ -966,13 +959,13 @@ func ProtobufToInterface(t *testing.T, val interface{}) interface{} { func RequireToCheckFunc(checFunc func(t require.TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{})) func(t *testing.T, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { return func(t *testing.T, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - checFunc(t, expected, actual, msgAndArgs) + checFunc(t, expected, actual, msgAndArgs...) } } func AssertToCheckFunc(checFunc func(t assert.TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool) func(t *testing.T, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { return func(t *testing.T, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - checFunc(t, expected, actual, msgAndArgs) + checFunc(t, expected, actual, msgAndArgs...) } } diff --git a/test/thingDescription.go b/test/thingDescription.go new file mode 100644 index 000000000..bbe9e8a11 --- /dev/null +++ b/test/thingDescription.go @@ -0,0 +1,33 @@ +package test + +import ( + "sort" + "testing" + + "github.com/stretchr/testify/require" + wotTD "github.com/web-of-things-open-source/thingdescription-go/thingDescription" +) + +func CmpThingDescription(t *testing.T, expected, got *wotTD.ThingDescription) { + sort.Strings(expected.Type.StringArray) + sort.Strings(got.Type.StringArray) + sortProperties := func(td *wotTD.ThingDescription) { + for key, prop := range td.Properties { + for idx, form := range prop.Forms { + if form.Op.StringArray == nil { + continue + } + sort.Strings(form.Op.StringArray) + prop.Forms[idx] = form + } + if prop.Type == nil { + continue + } + sort.Strings(prop.Type.StringArray) + td.Properties[key] = prop + } + } + sortProperties(expected) + sortProperties(got) + require.Equal(t, expected, got) +} diff --git a/test/virtual-device/cmd/main.go b/test/virtual-device/cmd/main.go index d1fe26855..c4fc551ba 100644 --- a/test/virtual-device/cmd/main.go +++ b/test/virtual-device/cmd/main.go @@ -9,6 +9,7 @@ import ( "crypto/tls" "crypto/x509" "encoding/pem" + "errors" "flag" "fmt" "os" @@ -73,9 +74,9 @@ func generateIdentityCert(deviceID string, signerCert []*x509.Certificate, signe } func makeVerifyCertificate(signerCert []*x509.Certificate) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { - return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + return func(rawCerts [][]byte, _ [][]*x509.Certificate) error { if len(rawCerts) == 0 { - return fmt.Errorf("empty certificates chain") + return errors.New("empty certificates chain") } intermediateCAPool := x509.NewCertPool() certs := make([]*x509.Certificate, 0, len(rawCerts)) @@ -191,7 +192,7 @@ func signUpDevice(ctx context.Context, deviceID string, co *client.Conn) (servic return service.CoapSignUpResponse{}, err } if signUpResp.AccessToken == "" { - return service.CoapSignUpResponse{}, fmt.Errorf("cannot sign up device: empty access token") + return service.CoapSignUpResponse{}, errors.New("cannot sign up device: empty access token") } return signUpResp, nil } @@ -286,12 +287,12 @@ func publishResources(ctx context.Context, deviceID string, co *client.Conn, num }) } - wkRd := wkRd{ + wk := wkRd{ DeviceID: deviceID, Links: links, TimeToLive: 0, } - inputCbor, err := cbor.Encode(wkRd) + inputCbor, err := cbor.Encode(wk) if err != nil { return err } @@ -341,7 +342,7 @@ func encodePlatformResource(w *responsewriter.ResponseWriter[*client.Conn]) []by pCbor, err := cbor.Encode(p) if err != nil { fmt.Printf("cannot encode platform: %v", err) - err := w.SetResponse(codes.Content, message.AppOcfCbor, bytes.NewReader([]byte{})) + err = w.SetResponse(codes.Content, message.AppOcfCbor, bytes.NewReader([]byte{})) if err != nil { fmt.Printf(errSetResponseFmt, err) } @@ -426,7 +427,7 @@ func processBatchResourceLinks(w *responsewriter.ResponseWriter[*client.Conn], d inputCbor, err := cbor.Encode(data) if err != nil { fmt.Printf("cannot encode resource data: %v", err) - err := w.SetResponse(codes.Content, message.AppOcfCbor, bytes.NewReader([]byte{})) + err = w.SetResponse(codes.Content, message.AppOcfCbor, bytes.NewReader([]byte{})) if err != nil { fmt.Printf(errSetResponseFmt, err) } @@ -514,7 +515,7 @@ func processGetResourceLinks(w *responsewriter.ResponseWriter[*client.Conn], dev inputCbor, err := cbor.Encode(links) if err != nil { fmt.Printf("cannot encode resource links: %v", err) - err := w.SetResponse(codes.Content, message.AppOcfCbor, bytes.NewReader([]byte{})) + err = w.SetResponse(codes.Content, message.AppOcfCbor, bytes.NewReader([]byte{})) if err != nil { fmt.Printf(errSetResponseFmt, err) } diff --git a/test/virtual-device/virtualDevice.go b/test/virtual-device/virtualDevice.go index bbbfaf423..54b23096a 100644 --- a/test/virtual-device/virtualDevice.go +++ b/test/virtual-device/virtualDevice.go @@ -8,6 +8,7 @@ import ( "time" "github.com/google/uuid" + "github.com/plgd-dev/device/v2/bridge/resources/thingDescription" "github.com/plgd-dev/device/v2/schema" "github.com/plgd-dev/device/v2/schema/device" "github.com/plgd-dev/device/v2/schema/interfaces" @@ -20,6 +21,7 @@ import ( "github.com/plgd-dev/hub/v2/test" "github.com/plgd-dev/hub/v2/test/config" oauthTest "github.com/plgd-dev/hub/v2/test/oauth-server/test" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/sync/semaphore" "google.golang.org/grpc" @@ -28,7 +30,7 @@ import ( "google.golang.org/grpc/status" ) -func CreateDeviceResourceLinks(deviceID string, numResources int) []*commands.Resource { +func CreateDeviceResourceLinks(deviceID string, numResources int, tdEnabled bool) []*commands.Resource { resources := make([]*commands.Resource, 0, numResources) for i := 0; i < numResources; i++ { resources = append(resources, &commands.Resource{ @@ -59,10 +61,23 @@ func CreateDeviceResourceLinks(deviceID string, numResources int) []*commands.Re BitFlags: int32(schema.Observable | schema.Discoverable), }, }) + + if tdEnabled { + resources = append(resources, &commands.Resource{ + Href: thingDescription.ResourceURI, + DeviceId: deviceID, + ResourceTypes: []string{thingDescription.ResourceType}, + Interfaces: []string{interfaces.OC_IF_BASELINE, interfaces.OC_IF_R}, + Policy: &commands.Policy{ + BitFlags: int32(schema.Discoverable), + }, + }) + } + return resources } -func CreateDevice(ctx context.Context, t *testing.T, name string, deviceID string, numResources int, protocol commands.Connection_Protocol, isClient pb.IdentityStoreClient, raClient raPb.ResourceAggregateClient) { +func CreateDevice(ctx context.Context, t *testing.T, name string, deviceID string, numResources int, tdEnabled bool, protocol commands.Connection_Protocol, isClient pb.IdentityStoreClient, raClient raPb.ResourceAggregateClient) { const connID = "conn-Id" var conSeq uint64 incSeq := func() uint64 { @@ -72,7 +87,7 @@ func CreateDevice(ctx context.Context, t *testing.T, name string, deviceID strin _, err := isClient.AddDevice(ctx, &pb.AddDeviceRequest{ DeviceId: deviceID, }) - require.NoError(t, err) + assert.NoError(t, err) //nolint:testifylint for { _, err = raClient.UpdateDeviceMetadata(ctx, &commands.UpdateDeviceMetadataRequest{ @@ -80,10 +95,11 @@ func CreateDevice(ctx context.Context, t *testing.T, name string, deviceID strin CorrelationId: uuid.NewString(), Update: &commands.UpdateDeviceMetadataRequest_Connection{ Connection: &commands.Connection{ - Status: commands.Connection_ONLINE, - ConnectedAt: time.Now().UnixNano(), - Protocol: protocol, - ServiceId: "a0000000-0000-0000-0000-000000000099", + Status: commands.Connection_ONLINE, + ConnectedAt: time.Now().UnixNano(), + Protocol: protocol, + ServiceId: "a0000000-0000-0000-0000-000000000099", + LocalEndpoints: []string{"coaps+tcp://localhost:5684"}, }, }, TimeToLive: time.Now().Add(time.Hour).UnixNano(), @@ -100,10 +116,10 @@ func CreateDevice(ctx context.Context, t *testing.T, name string, deviceID strin // device is still not loaded to owner in resource-aggregate continue } - require.NoError(t, err) + assert.NoError(t, err) //nolint:testifylint } - resources := CreateDeviceResourceLinks(deviceID, numResources) + resources := CreateDeviceResourceLinks(deviceID, numResources, tdEnabled) pub := commands.PublishResourceLinksRequest{ DeviceId: deviceID, Resources: resources, @@ -113,7 +129,7 @@ func CreateDevice(ctx context.Context, t *testing.T, name string, deviceID strin }, } _, err = raClient.PublishResourceLinks(ctx, &pub) - require.NoError(t, err) + assert.NoError(t, err) //nolint:testifylint _, err = raClient.UpdateDeviceMetadata(ctx, &commands.UpdateDeviceMetadataRequest{ DeviceId: deviceID, @@ -130,7 +146,8 @@ func CreateDevice(ctx context.Context, t *testing.T, name string, deviceID strin Sequence: incSeq(), }, }) - require.NoError(t, err) + assert.NoError(t, err) //nolint:testifylint + for i := 0; i < numResources; i++ { _, err = raClient.NotifyResourceChanged(ctx, &commands.NotifyResourceChangedRequest{ ResourceId: commands.NewResourceID(deviceID, fmt.Sprintf("/res-%v", i)), @@ -144,8 +161,9 @@ func CreateDevice(ctx context.Context, t *testing.T, name string, deviceID strin }, Status: commands.Status_OK, }) - require.NoError(t, err) + assert.NoError(t, err) //nolint:testifylint } + _, err = raClient.NotifyResourceChanged(ctx, &commands.NotifyResourceChangedRequest{ ResourceId: commands.NewResourceID(deviceID, "/oic/d"), CommandMetadata: &commands.CommandMetadata{ @@ -158,7 +176,7 @@ func CreateDevice(ctx context.Context, t *testing.T, name string, deviceID strin }, Status: commands.Status_OK, }) - require.NoError(t, err) + assert.NoError(t, err) //nolint:testifylint _, err = raClient.NotifyResourceChanged(ctx, &commands.NotifyResourceChangedRequest{ ResourceId: commands.NewResourceID(deviceID, "/oic/p"), @@ -172,7 +190,7 @@ func CreateDevice(ctx context.Context, t *testing.T, name string, deviceID strin }, Status: commands.Status_OK, }) - require.NoError(t, err) + assert.NoError(t, err) //nolint:testifylint _, err = raClient.UpdateDeviceMetadata(ctx, &commands.UpdateDeviceMetadataRequest{ DeviceId: deviceID, @@ -189,13 +207,13 @@ func CreateDevice(ctx context.Context, t *testing.T, name string, deviceID strin Sequence: incSeq(), }, }) - require.NoError(t, err) + assert.NoError(t, err) } func CreateDevices(ctx context.Context, t *testing.T, numDevices int, numResourcesPerDevice int, protocol commands.Connection_Protocol) { ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t)) - isConn, err := grpc.Dial(config.IDENTITY_STORE_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + isConn, err := grpc.NewClient(config.IDENTITY_STORE_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -204,7 +222,7 @@ func CreateDevices(ctx context.Context, t *testing.T, numDevices int, numResourc }() isClient := pb.NewIdentityStoreClient(isConn) - raConn, err := grpc.Dial(config.RESOURCE_AGGREGATE_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + raConn, err := grpc.NewClient(config.RESOURCE_AGGREGATE_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ RootCAs: test.GetRootCertificatePool(t), }))) require.NoError(t, err) @@ -219,7 +237,7 @@ func CreateDevices(ctx context.Context, t *testing.T, numDevices int, numResourc err = sem.Acquire(ctx, 1) require.NoError(t, err) go func(i int) { - CreateDevice(ctx, t, fmt.Sprintf("dev-%v", i), uuid.NewString(), numResourcesPerDevice, protocol, isClient, raClient) + CreateDevice(ctx, t, fmt.Sprintf("dev-%v", i), uuid.NewString(), numResourcesPerDevice, false, protocol, isClient, raClient) sem.Release(1) }(i) } diff --git a/tools/cert-tool/Dockerfile b/tools/cert-tool/Dockerfile index 18eb73a6a..73dd69940 100644 --- a/tools/cert-tool/Dockerfile +++ b/tools/cert-tool/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.20.13-alpine AS build +FROM golang:1.22.3-alpine AS build ARG DIRECTORY ARG NAME ARG VERSION @@ -11,9 +11,13 @@ WORKDIR $GOPATH/src/github.com/plgd-dev/hub COPY go.mod go.sum ./ RUN go mod download COPY . . -RUN ( cd /usr/local/go && patch -p1 < $GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch ) +WORKDIR /usr/local/go +RUN ( patch -p1 < "$GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch" ) WORKDIR $GOPATH/src/github.com/plgd-dev/hub/tools/cert-tool -RUN CGO_ENABLED=0 go build -ldflags "-X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/cert-tool ./ +RUN CGO_ENABLED=0 go build \ + -ldflags "-X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o /go/bin/cert-tool \ + ./ FROM alpine:3.19 AS security-provider RUN addgroup -S nonroot \ @@ -23,4 +27,4 @@ FROM scratch AS service COPY --from=security-provider /etc/passwd /etc/passwd COPY --from=build /go/bin/cert-tool /usr/local/bin/cert-tool USER nonroot -ENTRYPOINT [ "/usr/local/bin/cert-tool" ] \ No newline at end of file +ENTRYPOINT [ "/usr/local/bin/cert-tool" ] diff --git a/tools/docker/Dockerfile.in b/tools/docker/Dockerfile.in index c120f554e..46e1e79b4 100644 --- a/tools/docker/Dockerfile.in +++ b/tools/docker/Dockerfile.in @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM golang:1.20.13-alpine AS build +FROM golang:1.22.3-alpine AS build ARG VERSION ARG COMMIT_DATE ARG SHORT_COMMIT @@ -11,10 +11,16 @@ COPY go.mod go.sum ./ RUN go mod download COPY . . RUN go mod vendor -RUN ( cd /usr/local/go && patch -p1 < $GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch ) -RUN ( cd ./vendor/golang.org/x/oauth2 && patch -p1 < $GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/golang_org_x_oauth2_propagate_error.patch ) +WORKDIR /usr/local/go +RUN ( patch -p1 < "$GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch" ) +WORKDIR $GOPATH/src/github.com/plgd-dev/hub/vendor/golang.org/x/oauth2 +RUN ( patch -p1 < "$GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/golang_org_x_oauth2_propagate_error.patch" ) WORKDIR $GOPATH/src/github.com/plgd-dev/hub/@DIRECTORY@ -RUN CGO_ENABLED=0 go build -mod=vendor -ldflags "-X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" -o /go/bin/@NAME@ ./cmd/service +RUN CGO_ENABLED=0 go build \ + -mod=vendor \ + -ldflags "-X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \ + -o /go/bin/@NAME@ \ + ./cmd/service FROM alpine:3.19 AS security-provider RUN apk add -U --no-cache ca-certificates @@ -26,4 +32,4 @@ COPY --from=security-provider /etc/passwd /etc/passwd COPY --from=security-provider /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=build /go/bin/@NAME@ /usr/local/bin/@NAME@ USER nonroot -ENTRYPOINT [ "/usr/local/bin/@NAME@" ] \ No newline at end of file +ENTRYPOINT [ "/usr/local/bin/@NAME@" ] diff --git a/tools/nats-server-config-reloader/Dockerfile b/tools/nats-server-config-reloader/Dockerfile deleted file mode 100644 index 20aaf5bfd..000000000 --- a/tools/nats-server-config-reloader/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM golang:1.20.13-alpine AS build -RUN apk add --no-cache curl git build-base -WORKDIR $GOPATH/src/github.com/plgd-dev/hub -COPY go.mod go.sum ./ -RUN go mod download -COPY . . -RUN go mod vendor -RUN ( cd /usr/local/go && patch -p1 < $GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/shrink_tls_conn.patch ) -RUN ( cd ./vendor/golang.org/x/oauth2 && patch -p1 < $GOPATH/src/github.com/plgd-dev/hub/tools/docker/patches/golang_org_x_oauth2_propagate_error.patch ) -WORKDIR $GOPATH/src/github.com/plgd-dev/hub/tools/nats-server-config-reloader -RUN CGO_ENABLED=0 go build -mod=vendor -o /go/bin/nats-server-config-reloader . - -FROM alpine:3.19 AS security-provider -RUN apk add -U --no-cache ca-certificates - -FROM scratch AS service -COPY --from=security-provider /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ -COPY --from=build /go/bin/nats-server-config-reloader /usr/local/bin/nats-server-config-reloader -ENTRYPOINT [ /usr/local/bin/nats-server-config-reloader ] \ No newline at end of file diff --git a/tools/nats-server-config-reloader/main.go b/tools/nats-server-config-reloader/main.go deleted file mode 100644 index 8eba9a121..000000000 --- a/tools/nats-server-config-reloader/main.go +++ /dev/null @@ -1,119 +0,0 @@ -package main - -import ( - "context" - "errors" - "flag" - "fmt" - "log" - "os" - "os/signal" - "strings" - "syscall" - - "github.com/plgd-dev/hub/v2/tools/nats-server-config-reloader/pkg/natsreloader" -) - -var ( - BuildTime = "build-time-not-set" - GitInfo = "gitinfo-not-set" - Version = "version-not-set" -) - -const errorFmt = natsreloader.ErrorFmt - -// StringSet is a wrapper for []string to allow using it with the flags package. -type StringSet []string - -func (s *StringSet) String() string { - return strings.Join([]string(*s), ", ") -} - -// Set appends the value provided to the list of strings. -func (s *StringSet) Set(val string) error { - *s = append(*s, val) - return nil -} - -func main() { - fs := flag.NewFlagSet("nats-server-config-reloader", flag.ExitOnError) - flag.Usage = func() { - fmt.Fprintf(os.Stderr, "Usage: nats-server-config-reloader [options...]\n\n") - fs.PrintDefaults() - fmt.Fprintf(os.Stderr, "\n") - } - - // Help and version - var ( - showHelp bool - showVersion bool - fileSet StringSet - customSignal int - ) - - nconfig := &natsreloader.Config{} - fs.BoolVar(&showHelp, "h", false, "Show help") - fs.BoolVar(&showHelp, "help", false, "Show help") - fs.BoolVar(&showVersion, "v", false, "Show version") - fs.BoolVar(&showVersion, "version", false, "Show version") - - fs.StringVar(&nconfig.PidFile, "P", "/var/run/nats/gnatsd.pid", "NATS Server Pid File") - fs.StringVar(&nconfig.PidFile, "pid", "/var/run/nats/gnatsd.pid", "NATS Server Pid File") - fs.Var(&fileSet, "c", "NATS Server Config File (may be repeated to specify more than one)") - fs.Var(&fileSet, "config", "NATS Server Config File (may be repeated to specify more than one)") - fs.IntVar(&nconfig.MaxRetries, "max-retries", 5, "Max attempts to trigger reload") - fs.IntVar(&nconfig.RetryWaitSecs, "retry-wait-secs", 2, "Time to back off when reloading fails before retrying") - fs.IntVar(&customSignal, "signal", 1, "Signal to send to the NATS Server process (default SIGHUP 1)") - - err := fs.Parse(os.Args[1:]) - if err != nil { - fmt.Fprintf(os.Stderr, errorFmt, err) - os.Exit(1) - } - - nconfig.ConfigFiles = fileSet - if len(fileSet) == 0 { - nconfig.ConfigFiles = []string{"/etc/nats-config/gnatsd.conf"} - } - nconfig.Signal = syscall.Signal(customSignal) - - switch { - case showHelp: - flag.Usage() - os.Exit(0) - case showVersion: - fmt.Fprintf(os.Stderr, "NATS Server Config Reloader v%s (%s, %s)\n", Version, GitInfo, BuildTime) - os.Exit(0) - } - r, err := natsreloader.NewReloader(nconfig) - if err != nil { - fmt.Fprintf(os.Stderr, errorFmt, err) - os.Exit(1) - } - - // Signal handling. - go func() { - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) - - for sig := range c { - log.Printf("Trapped \"%v\" signal\n", sig) - switch sig { - case syscall.SIGINT: - log.Println("Exiting...") - os.Exit(0) - return - case syscall.SIGTERM: - _ = r.Stop() - return - } - } - }() - - log.Printf("Starting NATS Server Reloader v%s\n", Version) - err = r.Run(context.Background()) - if err != nil && !errors.Is(err, context.Canceled) { - fmt.Fprintf(os.Stderr, errorFmt, err.Error()) - os.Exit(1) - } -} diff --git a/tools/nats-server-config-reloader/pkg/natsreloader/natsreloader.go b/tools/nats-server-config-reloader/pkg/natsreloader/natsreloader.go deleted file mode 100644 index 51c4c60bd..000000000 --- a/tools/nats-server-config-reloader/pkg/natsreloader/natsreloader.go +++ /dev/null @@ -1,355 +0,0 @@ -package natsreloader - -import ( - "bytes" - "context" - "crypto/sha256" - "fmt" - "io" - "log" - "math/rand" - "os" - "path/filepath" - "sort" - "strconv" - "time" - - "github.com/fsnotify/fsnotify" -) - -const ErrorFmt = "Error: %s\n" - -// Config represents the configuration of the reloader. -type Config struct { - PidFile string - ConfigFiles []string - MaxRetries int - RetryWaitSecs int - Signal os.Signal -} - -// Reloader monitors the state from a single server config file -// and sends signal on updates. -type Reloader struct { - *Config - - // proc represents the NATS Server process which will - // be signaled. - proc *os.Process - - // pid is the last known PID from the NATS Server. - pid int - - // quit shutsdown the reloader. - quit func() -} - -func (r *Reloader) waitForProcess() error { - var proc *os.Process - var pid int - attempts := 0 - - startTime := time.Now() - for { - pidfile, err := os.ReadFile(r.PidFile) - if err != nil { - goto WaitAndRetry - } - - pid, err = strconv.Atoi(string(pidfile)) - if err != nil { - goto WaitAndRetry - } - - proc, err = os.FindProcess(pid) - if err != nil { - goto WaitAndRetry - } - break - - WaitAndRetry: - log.Printf(ErrorFmt, err) - attempts++ - if attempts > r.MaxRetries { - return fmt.Errorf("too many errors attempting to find server process") - } - time.Sleep(time.Duration(r.RetryWaitSecs) * time.Second) - } - - if attempts > 0 { - log.Printf("found pid from pidfile %q after %v failed attempts (%v time after start)", - r.PidFile, attempts, time.Since(startTime)) - } - - r.pid = pid - r.proc = proc - return nil -} - -func removeDuplicateStrings(s []string) []string { - if len(s) < 1 { - return s - } - - sort.Strings(s) - prev := 1 - for curr := 1; curr < len(s); curr++ { - if s[curr-1] != s[curr] { - s[prev] = s[curr] - prev++ - } - } - - return s[:prev] -} - -func calcDigest(filePath string) ([]byte, error) { - h := sha256.New() - f, err := os.Open(filePath) - if err != nil { - return nil, err - } - defer func() { - _ = f.Close() - }() - if _, err := io.Copy(h, f); err != nil { - return nil, err - } - return h.Sum(nil), nil -} - -func handleEvent(event fsnotify.Event, lastConfigAppliedCache map[string][]byte, updatedFiles, deletedFiles []string) ([]string, []string) { - if event.Op&fsnotify.Remove == fsnotify.Remove { - // We don't get a Remove event for the directory itself, so - // we need to detect that separately. - return updatedFiles, append(deletedFiles, event.Name) - } - _, err := os.Stat(event.Name) - if err != nil { - // Beware that this means that we won't reconfigure if a file - // is permanently removed. We want to support transient - // disappearance, waiting for the new content, and have not set - // up any sort of longer-term timers to detect permanent - // deletion. - // If you really need this, then switch a file to be empty - // before removing if afterwards. - return updatedFiles, deletedFiles - } - - if len(updatedFiles) > 0 { - return updatedFiles, deletedFiles - } - digest, err := calcDigest(event.Name) - if err != nil { - log.Printf(ErrorFmt, err) - return updatedFiles, deletedFiles - } - - lastConfigHash, ok := lastConfigAppliedCache[event.Name] - if ok && bytes.Equal(lastConfigHash, digest) { - return updatedFiles, deletedFiles - } - - log.Printf("changed config; file=%q existing=%v total-files=%d", - event.Name, ok, len(lastConfigAppliedCache)) - lastConfigAppliedCache[event.Name] = digest - return append(updatedFiles, event.Name), deletedFiles -} - -// handleEvents handles all events in the queue. It returns the updated and deleted files and can contain duplicates. -func handleEvents(configWatcher *fsnotify.Watcher, event fsnotify.Event, lastConfigAppliedCache map[string][]byte) ([]string, []string) { - updatedFiles, deletedFiles := handleEvent(event, lastConfigAppliedCache, make([]string, 0, 16), make([]string, 0, 16)) - for { - select { - case event := <-configWatcher.Events: - updatedFiles, deletedFiles = handleEvent(event, lastConfigAppliedCache, updatedFiles, deletedFiles) - default: - return updatedFiles, deletedFiles - } - } -} - -func handleDeletedFiles(deletedFiles []string, configWatcher *fsnotify.Watcher, lastConfigAppliedCache map[string][]byte) ([]string, []string) { - log.Printf("Ticker is running with deletedFiles %v", deletedFiles) - newDeletedFiles := make([]string, 0, len(deletedFiles)) - updated := make([]string, 0, len(deletedFiles)) - for _, f := range deletedFiles { - if err := configWatcher.Add(f); err != nil { - newDeletedFiles = append(newDeletedFiles, f) - } else { - updated, _ = handleEvent(fsnotify.Event{Name: f, Op: fsnotify.Create}, lastConfigAppliedCache, updated, nil) - } - } - return removeDuplicateStrings(updated), newDeletedFiles -} - -func (r *Reloader) init() (*fsnotify.Watcher, map[string][]byte, error) { - err := r.waitForProcess() - if err != nil { - return nil, nil, err - } - - configWatcher, err := fsnotify.NewWatcher() - if err != nil { - return nil, nil, err - } - - // Follow configuration updates in the directory where - // the config file is located and trigger reload when - // it is either recreated or written into. - for i := range r.ConfigFiles { - // Ensure our paths are canonical - r.ConfigFiles[i], _ = filepath.Abs(r.ConfigFiles[i]) - } - r.ConfigFiles = removeDuplicateStrings(r.ConfigFiles) - // Follow configuration file updates and trigger reload when - // it is either recreated or written into. - for i := range r.ConfigFiles { - // Watch files individually for https://github.com/kubernetes/kubernetes/issues/112677 - if err := configWatcher.Add(r.ConfigFiles[i]); err != nil { - _ = configWatcher.Close() - return nil, nil, err - } - log.Printf("watching file: %v", r.ConfigFiles[i]) - } - - // lastConfigAppliedCache is the last config update - // applied by us - lastConfigAppliedCache := make(map[string][]byte) - - // Preload config hashes, so we know their digests - // up front and avoid potentially reloading when unnecessary. - for _, configFile := range r.ConfigFiles { - digest, err := calcDigest(configFile) - if err != nil { - _ = configWatcher.Close() - return nil, nil, err - } - lastConfigAppliedCache[configFile] = digest - } - - // If the two pids don't match then os.FindProcess() has done something - // rather hinkier than we expect, but log them both just in case on some - // future platform there's a weird namespace issue, as a difference will - // help with debugging. - log.Printf("Live, ready to kick pid %v (live, from %v spec) based on any of %v files", - r.proc.Pid, r.pid, len(lastConfigAppliedCache)) - - if len(lastConfigAppliedCache) == 0 { - log.Printf("Error: no watched config files cached; input spec was: %#v", - r.ConfigFiles) - } - return configWatcher, lastConfigAppliedCache, nil -} - -func (r *Reloader) reload(updatedFiles []string) error { - attempts := 0 - for { - log.Printf("Sending signal '%s' to server to reload configuration due to: %s", r.Signal.String(), updatedFiles) - err := r.proc.Signal(r.Signal) - if err == nil { - return nil - } - log.Printf("Error during reload: %s\n", err) - if attempts > r.MaxRetries { - return fmt.Errorf("too many errors (%v) attempting to signal server to reload: %w", attempts, err) - } - delay := retryJitter(time.Duration(r.RetryWaitSecs) * time.Second) - log.Printf("Wait and retrying after some time [%v] ...", delay) - time.Sleep(delay) - attempts++ - } -} - -// Run starts the main loop. -func (r *Reloader) Run(ctx context.Context) error { - ctx, cancel := context.WithCancel(ctx) - r.quit = func() { - cancel() - } - - configWatcher, lastConfigAppliedCache, err := r.init() - if err != nil { - return err - } - defer func() { - _ = configWatcher.Close() - }() - - // We use a ticker to re-add deleted files to the watcher - t := time.NewTicker(time.Second) - t.Stop() - defer t.Stop() - var tickerRunning bool - var deletedFiles []string - var updatedFiles []string - - for { - select { - case <-ctx.Done(): - return nil - case <-t.C: - updatedFiles, deletedFiles = handleDeletedFiles(deletedFiles, configWatcher, lastConfigAppliedCache) - if len(deletedFiles) == 0 { - // No more deleted files, stop the ticker - t.Stop() - tickerRunning = false - } - if len(updatedFiles) > 0 { - // Send signal to reload the config - log.Printf("Updated files: %v", updatedFiles) - break - } - continue - // Check if the process is still alive - case event := <-configWatcher.Events: - updated, deleted := handleEvents(configWatcher, event, lastConfigAppliedCache) - updatedFiles = removeDuplicateStrings(updated) - deletedFiles = removeDuplicateStrings(append(deletedFiles, deleted...)) - if !tickerRunning { - // Start the ticker to re-add deleted files - t.Reset(time.Second) - tickerRunning = true - } - if len(updatedFiles) > 0 { - // Send signal to reload the config - log.Printf("Updated files: %v", updatedFiles) - break - } - continue - case err := <-configWatcher.Errors: - log.Printf(ErrorFmt, err) - continue - } - // Configuration was updated, try to do reload for a few times - // otherwise give up and wait for next event. - err := r.reload(updatedFiles) - if err != nil { - return err - } - updatedFiles = nil - } -} - -// Stop shutsdown the process. -func (r *Reloader) Stop() error { - log.Println("Shutting down...") - r.quit() - return nil -} - -// NewReloader returns a configured NATS server reloader. -func NewReloader(config *Config) (*Reloader, error) { - return &Reloader{ - Config: config, - }, nil -} - -// retryJitter helps avoid trying things at synchronized times, thus improving -// resiliency in aggregate. -func retryJitter(base time.Duration) time.Duration { - b := float64(base) - // 10% +/- - offset := rand.Float64()*0.2 - 0.1 - return time.Duration(b + offset) -} diff --git a/tools/nats-server-config-reloader/pkg/natsreloader/natsreloadertest/natsreloader_test.go b/tools/nats-server-config-reloader/pkg/natsreloader/natsreloadertest/natsreloader_test.go deleted file mode 100644 index d25772ffc..000000000 --- a/tools/nats-server-config-reloader/pkg/natsreloader/natsreloadertest/natsreloader_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package natsreloadertest - -import ( - "context" - "errors" - "fmt" - "os" - "os/signal" - "sync" - "syscall" - "testing" - "time" - - "github.com/plgd-dev/hub/v2/tools/nats-server-config-reloader/pkg/natsreloader" -) - -var ( - configContents = `port = 2222` - newConfigContents = `port = 2222 -someOtherThing = "bar" -` -) - -func TestReloader(t *testing.T) { - // Setup a pidfile that points to us - pid := os.Getpid() - pidfile, err := os.CreateTemp(os.TempDir(), "nats-pid-") - if err != nil { - t.Fatal(err) - } - - p := fmt.Sprintf("%d", pid) - if _, err := pidfile.WriteString(p); err != nil { - t.Fatal(err) - } - defer os.Remove(pidfile.Name()) - - // Create tempfile with contents, then update it - nconfig := &natsreloader.Config{ - PidFile: pidfile.Name(), - ConfigFiles: []string{}, - Signal: syscall.SIGHUP, - } - - var configFiles []*os.File - for i := 0; i < 2; i++ { - configFile, err := os.CreateTemp(os.TempDir(), "nats-conf-") - if err != nil { - t.Fatal(err) - } - defer os.Remove(configFile.Name()) - - if _, err := configFile.WriteString(configContents); err != nil { - t.Fatal(err) - } - configFiles = append(configFiles, configFile) - nconfig.ConfigFiles = append(nconfig.ConfigFiles, configFile.Name()) - } - - r, err := natsreloader.NewReloader(nconfig) - if err != nil { - t.Fatal(err) - } - - signals := 0 - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - var sigsMu sync.Mutex - - // Signal handling. - go func() { - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGHUP) - - // Success when receiving the first signal - for range c { - sigsMu.Lock() - signals++ - sigsMu.Unlock() - } - }() - - go func() { - // This is terrible, but we need this thread to wait until r.Run(ctx) has finished starting up - // before we start mucking with the file. - // There isn't any other good way to synchronize on this happening. - time.Sleep(100 * time.Millisecond) - for _, configfile := range configFiles { - for i := 0; i < 5; i++ { - // Append some more stuff to the config - if _, err := configfile.WriteAt([]byte(newConfigContents), 0); err != nil { - return - } - time.Sleep(10 * time.Millisecond) - } - } - - // Create some random file in the same directory, shouldn't trigger an - // additional server signal. - configFile, err := os.CreateTemp(os.TempDir(), "foo") - if err != nil { - t.Log(err) - return - } - defer os.Remove(configFile.Name()) - time.Sleep(100 * time.Millisecond) - - cancel() - }() - - err = r.Run(ctx) - if err != nil && !errors.Is(err, context.Canceled) { - t.Fatal(err) - } - // We should have gotten only one signal for each configuration file - sigsMu.Lock() - got := signals - sigsMu.Unlock() - expected := len(configFiles) - if got != expected { - t.Fatalf("Wrong number of signals received. Expected: %v, got: %v", expected, got) - } -}
    INPROGRESSPENDING 1

    WAITING_FOR_REOURCE2

    DONE3

    2

    If done look to resource_updated even update resource failed for resource aggregate.

    TIMEOUT4

    FAIL53

    InvokeConfiguration InvokeConfigurationRequestAppliedConfiguration streamAppliedDeviceConfiguration stream

    streaming process of update configuration to invoker

    GetAppliedConfigurationsGetAppliedConfigurationsRequestAppliedConfiguration streamGetAppliedDeviceConfigurationsRequestAppliedDeviceConfiguration stream

    DeleteAppliedConfigurationsDeleteAppliedConfigurationsRequestDeleteAppliedConfigurationsResponseDeleteAppliedDeviceConfigurationsRequestDeleteAppliedDeviceConfigurationsResponse

    InvokeConfiguration POST/api/v1/configurations/{id}/api/v1/configurations/{configuration_id} *