From a6f39f1b24f25bea70d6a2bbce03cdb1129d4abb Mon Sep 17 00:00:00 2001 From: binchencoder <15811514091@163.com> Date: Sat, 19 Mar 2022 12:54:13 +0800 Subject: [PATCH 1/5] New branch for grpc-gateway-290 --- .bazelci/presubmit.yml | 18 +- .bazelversion | 2 +- .circleci/Dockerfile | 72 +- .circleci/config.yml | 126 +- .../protoc-gen-grpc-gateway/Dockerfile | 13 + .../plugins/protoc-gen-openapiv2/Dockerfile | 13 + .devcontainer/devcontainer.json | 25 + BUILD | 37 +- WORKSPACE | 80 +- examples/internal/integration/BUILD.bazel | 2 +- examples/internal/proto/examplepb/BUILD.bazel | 79 +- .../proto/examplepb/echo_service.pb.go | 758 ---- .../proto/examplepb/echo_service.pb.gw.go | 1522 ------- .../proto/examplepb/echo_service_grpc.pb.go | 230 - .../examplepb/standalone_echo_service.yaml | 2 +- .../examplepb/unannotated_echo_service.pb.go | 616 --- .../unannotated_echo_service.pb.gw.go | 3 - .../unannotated_echo_service_grpc.pb.go | 158 - gateway/internal/casing/BUILD.bazel | 8 +- gateway/internal/descriptor/BUILD.bazel | 59 +- .../internal/descriptor/apiconfig/BUILD.bazel | 10 +- .../descriptor/grpc_api_configuration.go | 2 +- .../descriptor/openapi_configuration.go | 2 +- .../descriptor/openapiconfig/BUILD.bazel | 10 +- .../openapiconfig/openapiconfig.pb.go | 18 +- gateway/internal/descriptor/registry.go | 135 +- gateway/internal/descriptor/registry_test.go | 117 +- gateway/internal/descriptor/services.go | 5 +- gateway/internal/descriptor/services_test.go | 98 + gateway/internal/descriptor/types.go | 30 +- gateway/internal/descriptor/types_test.go | 10 +- gateway/internal/generator/BUILD.bazel | 13 +- gateway/protoc-gen-grpc-gateway/BUILD.bazel | 19 +- .../internal/gengateway/BUILD.bazel | 36 +- .../internal/gengateway/generator.go | 15 +- .../internal/gengateway/generator_test.go | 1 + .../internal/gengateway/template.go | 44 +- .../internal/gengateway/template_test.go | 184 +- gateway/protoc-gen-grpc-gateway/main.go | 4 + gateway/protoc-gen-openapiv2/BUILD.bazel | 21 +- gateway/protoc-gen-openapiv2/defs.bzl | 179 +- .../internal/genopenapi/BUILD.bazel | 75 +- .../internal/genopenapi/cycle_test.go | 41 + .../internal/genopenapi/format.go | 43 + .../internal/genopenapi/generator.go | 37 +- .../internal/genopenapi/naming.go | 110 + .../internal/genopenapi/template.go | 1144 +++-- .../internal/genopenapi/template_test.go | 3702 ----------------- .../internal/genopenapi/types.go | 287 +- gateway/protoc-gen-openapiv2/main.go | 79 +- gateway/protoc-gen-openapiv2/main_test.go | 229 +- .../protoc-gen-openapiv2/options/BUILD.bazel | 8 +- .../options/annotations.pb.go | 76 +- .../options/annotations.proto | 10 +- .../options/openapiv2.pb.go | 1096 ++--- .../options/openapiv2.proto | 68 +- gateway/runtime/BUILD.bazel | 76 +- gateway/runtime/context.go | 58 +- gateway/runtime/context_test.go | 31 +- gateway/runtime/convert.go | 10 +- gateway/runtime/convert_test.go | 22 +- gateway/runtime/errors.go | 38 +- gateway/runtime/errors_test.go | 10 + gateway/runtime/fieldmask.go | 36 +- gateway/runtime/handler.go | 27 +- gateway/runtime/handler_test.go | 6 + .../runtime/internal/examplepb/BUILD.bazel | 9 +- .../runtime/internal/examplepb/proto3.pb.go | 650 +-- .../runtime/internal/examplepb/proto3.proto | 5 +- gateway/runtime/marshal_json_test.go | 255 -- gateway/runtime/marshal_jsonpb.go | 37 + gateway/runtime/marshal_jsonpb_test.go | 877 ---- gateway/runtime/marshal_proto_test.go | 91 - gateway/runtime/mux.go | 191 +- gateway/runtime/mux_test.go | 307 +- gateway/runtime/pattern.go | 158 +- gateway/runtime/pattern_test.go | 590 --- gateway/runtime/proto2_convert.go | 80 - gateway/runtime/query.go | 16 +- gateway/runtime/query_test.go | 610 --- go.mod | 40 +- go.sum | 26 + httpoptions/BUILD.bazel | 32 +- httpoptions/annotations.pb.go | 185 +- httpoptions/http.pb.go | 364 +- renovate.json | 53 + repositories.bzl | 104 +- 87 files changed, 4683 insertions(+), 12092 deletions(-) create mode 100644 .circleci/plugins/protoc-gen-grpc-gateway/Dockerfile create mode 100644 .circleci/plugins/protoc-gen-openapiv2/Dockerfile create mode 100644 .devcontainer/devcontainer.json delete mode 100755 examples/internal/proto/examplepb/echo_service.pb.go delete mode 100755 examples/internal/proto/examplepb/echo_service.pb.gw.go delete mode 100755 examples/internal/proto/examplepb/echo_service_grpc.pb.go delete mode 100644 examples/internal/proto/examplepb/unannotated_echo_service.pb.go delete mode 100755 examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go delete mode 100755 examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go mode change 100644 => 100755 gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go create mode 100644 gateway/protoc-gen-openapiv2/internal/genopenapi/cycle_test.go create mode 100644 gateway/protoc-gen-openapiv2/internal/genopenapi/format.go create mode 100644 gateway/protoc-gen-openapiv2/internal/genopenapi/naming.go delete mode 100644 gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go mode change 100644 => 100755 gateway/protoc-gen-openapiv2/options/annotations.pb.go mode change 100644 => 100755 gateway/protoc-gen-openapiv2/options/openapiv2.pb.go mode change 100644 => 100755 gateway/runtime/internal/examplepb/proto3.pb.go delete mode 100644 gateway/runtime/marshal_json_test.go delete mode 100644 gateway/runtime/marshal_jsonpb_test.go delete mode 100644 gateway/runtime/marshal_proto_test.go delete mode 100644 gateway/runtime/pattern_test.go delete mode 100644 gateway/runtime/proto2_convert.go delete mode 100644 gateway/runtime/query_test.go mode change 100644 => 100755 httpoptions/annotations.pb.go mode change 100644 => 100755 httpoptions/http.pb.go create mode 100644 renovate.json diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index a0da2fc..58e328a 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -4,29 +4,19 @@ platforms: build_flags: - "--build_tag_filters=-nolinux" build_targets: - - "..." + - "//..." test_flags: - "--features=race" - "--test_tag_filters=-nolinux" test_targets: - - "..." - ubuntu1604: - build_flags: - - "--build_tag_filters=-nolinux" - build_targets: - - "..." - test_flags: - - "--features=race" - - "--test_tag_filters=-nolinux" - test_targets: - - "..." + - "//..." macos: build_flags: - "--build_tag_filters=-nomacos" build_targets: - - "..." + - "//..." test_flags: - "--features=race" - "--test_tag_filters=-nomacos" test_targets: - - "..." + - "//..." diff --git a/.bazelversion b/.bazelversion index 1545d96..af8c8ec 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -3.5.0 +4.2.2 diff --git a/.circleci/Dockerfile b/.circleci/Dockerfile index 0c649ac..a3f1108 100644 --- a/.circleci/Dockerfile +++ b/.circleci/Dockerfile @@ -1,41 +1,53 @@ -FROM golang:1.15.3 +FROM golang:1.18.0 -# Warm apt cache and install dependencies -# bzip2 is required by the node_tests (to extract its dependencies). -# patch is required by bazel tests +ENV NVM_DIR="/usr/local/share/nvm" +ENV NVM_SYMLINK_CURRENT=true \ + PATH=${NVM_DIR}/current/bin:${PATH} + +ARG VSCODE_SCRIPTS_VERSION="v0.193.0" +ARG NODE_VERSION="10" +# Run some common installation scripts for a nicer dev environment. In order: +# Used to create non-root user and update system packages +# https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/common.md +# We use this to install Go tools used by gopls +# https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/go.md +# We use this to install Node +# https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/node.md RUN apt-get update && \ - apt-get install -y wget unzip \ - openjdk-11-jre \ - bzip2 \ - patch + wget "https://raw.githubusercontent.com/microsoft/vscode-dev-containers/${VSCODE_SCRIPTS_VERSION}/script-library/common-debian.sh" && \ + chmod +x ./common-debian.sh && \ + ./common-debian.sh false vscode automatic automatic true false && \ + wget "https://raw.githubusercontent.com/microsoft/vscode-dev-containers/${VSCODE_SCRIPTS_VERSION}/script-library/go-debian.sh" && \ + chmod +x ./go-debian.sh && \ + ./go-debian.sh none /usr/local/go /go vscode false true && \ + wget "https://raw.githubusercontent.com/microsoft/vscode-dev-containers/${VSCODE_SCRIPTS_VERSION}/script-library/node-debian.sh" && \ + chmod +x ./node-debian.sh && \ + ./node-debian.sh "${NVM_DIR}" "${NODE_VERSION}" vscode true && \ + rm common-debian.sh go-debian.sh node-debian.sh && \ + DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \ + wget \ + unzip \ + openjdk-11-jre \ + bzip2 \ + patch && \ + apt-get clean -y && \ + rm -rf /var/lib/apt/lists/* # Install swagger-codegen ENV SWAGGER_CODEGEN_VERSION=2.4.8 RUN wget https://repo1.maven.org/maven2/io/swagger/swagger-codegen-cli/${SWAGGER_CODEGEN_VERSION}/swagger-codegen-cli-${SWAGGER_CODEGEN_VERSION}.jar \ - -O /usr/local/bin/swagger-codegen-cli.jar - -# Wrap the jar for swagger-codgen -RUN echo -e '#!/bin/bash\njava -jar /usr/local/bin/swagger-codegen-cli.jar "$@"' > /usr/local/bin/swagger-codegen && \ + -O /usr/local/bin/swagger-codegen-cli.jar && \ + echo -e '#!/bin/bash\njava -jar /usr/local/bin/swagger-codegen-cli.jar "$@"' > /usr/local/bin/swagger-codegen && \ chmod +x /usr/local/bin/swagger-codegen -# Install protoc -ENV PROTOC_VERSION=3.12.0 -RUN wget https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip \ - -O /protoc-${PROTOC_VERSION}-linux-x86_64.zip && \ - unzip /protoc-${PROTOC_VERSION}-linux-x86_64.zip -d /usr/local/ && \ - rm -f /protoc-${PROTOC_VERSION}-linux-x86_64.zip - -# Install node, used by NVM -ENV NODE_VERSION=v10.16.3 -ENV NVM_VERSION=v0.35.0 -RUN wget -qO- https://raw.githubusercontent.com/creationix/nvm/${NVM_VERSION}/install.sh | bash - # Install Bazelisk as bazel to manage Bazel -RUN go get github.com/bazelbuild/bazelisk && \ +RUN go install github.com/bazelbuild/bazelisk@latest && \ mv $(which bazelisk) /usr/local/bin/bazel -# Clean up -RUN apt-get autoremove -y && \ - apt-get remove -y wget \ - unzip && \ - rm -rf /var/lib/apt/lists/* +# Install buildifier for bazel formatting +RUN go install github.com/bazelbuild/buildtools/buildifier@latest + +# Give vscode ownership of GOPATH +RUN chown -R vscode: /go + +USER vscode diff --git a/.circleci/config.yml b/.circleci/config.yml index 4556a74..5894410 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ commands: steps: - run: | cat > .bazelrc \<< EOF - startup --output_base /root/.cache/_grpc_gateway_bazel + startup --output_base /home/vscode/.cache/_ease_gateway_bazel build --test_output errors build --features race # Workaround https://github.com/bazelbuild/bazel/issues/3645 @@ -16,9 +16,9 @@ commands: EOF generate: steps: - - run: make realclean - - run: make examples - - run: make testproto + - run: make install + - run: make clean + - run: make generate - run: go mod tidy renovate_git_amend_push: description: Git amend and push changes @@ -28,7 +28,7 @@ commands: if output=$(git status --porcelain) && [ ! -z "$output" ]; then git config user.name "Renovate Bot" git config user.email "bot@renovateapp.com" - git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/binchencoder/ease-gateway.git + git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/grpc-ecosystem/grpc-gateway.git git commit --amend --no-edit git push --force-with-lease origin ${CIRCLE_BRANCH} fi @@ -36,10 +36,10 @@ commands: executors: build-env: environment: - ## Split key to avoid github revoking it - password0: '99544cdcb19ad4e3fd64' - password1: '3ec86b2e5a431be2d72c' - GLOG_logtostderr: '1' + ## Split key to avoid github revoking it + password0: "99544cdcb19ad4e3fd64" + password1: "3ec86b2e5a431be2d72c" + GLOG_logtostderr: "1" docker: - image: docker.pkg.github.com/binchencoder/ease-gateway/build-env:1.15 auth: @@ -49,74 +49,44 @@ executors: jobs: build: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - run: go build ./... test: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - run: go test -race -coverprofile=coverage.txt ./... - run: bash <(curl -s https://codecov.io/bash) node_test: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - run: go mod vendor - run: > - . $HOME/.nvm/nvm.sh && cd examples/internal/browser && npm install gulp-cli && npm install && ./node_modules/.bin/gulp generate: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - generate - run: git diff --exit-code - lint: - executor: build-env - working_directory: /src/ease-gateway - steps: - - checkout - - restore_cache: - keys: - - v1-staticcheck-cache-{{ checksum "go.sum" }} - - v1-staticcheck-cache- - - run: - name: Install staticcheck outside local module - command: | - cd $(mktemp -d) && - go mod init tmp && - go get honnef.co/go/tools/cmd/staticcheck - - run: staticcheck ./... - - save_cache: - key: v1-staticcheck-cache-{{ checksum "go.sum" }} - paths: - - /root/.cache/go-build - - /root/.cache/staticcheck - fuzzit: - docker: - - image: fuzzitdev/fuzzit:golang1.12-stretch-llvm9 - working_directory: /src/ease-gateway - steps: - - checkout - - setup_remote_docker - - run: ./fuzzit.sh bazel: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - restore_cache: keys: - - v2-bazel-cache-{{ checksum "repositories.bzl" }} - - v2-bazel-cache- + - v3-bazel-cache-{{ checksum "repositories.bzl" }} + - v3-bazel-cache- - configure_bazel - run: name: Check that Bazel BUILD files are up-to-date @@ -137,12 +107,12 @@ jobs: name: Run tests with Bazel command: bazel test //... - save_cache: - key: v2-bazel-cache-{{ checksum "repositories.bzl" }} + key: v3-bazel-cache-{{ checksum "repositories.bzl" }} paths: - - /root/.cache/_grpc_gateway_bazel + - /home/vscode/.cache/_ease_gateway_bazel gorelease: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - run: @@ -151,23 +121,55 @@ jobs: cd $(mktemp -d) && go mod init tmp && go get golang.org/x/exp/cmd/gorelease@latest - - run: gorelease -base=v2.0.0 + - run: gorelease -base=v2.8.0 + push_bsr_plugins: + docker: + - image: circleci/golang + steps: + - setup_remote_docker + - checkout + - run: echo "${BUF_API_TOKEN}" | docker login --username grpcgatewaybot --password-stdin plugins.buf.build + - run: | + cd .circleci/plugins/protoc-gen-grpc-gateway && + docker build -t plugins.buf.build/grpc-ecosystem/grpc-gateway:${CIRCLE_TAG}-1 --build-arg=RELEASE_VERSION=${CIRCLE_TAG} . && + docker push plugins.buf.build/grpc-ecosystem/grpc-gateway:${CIRCLE_TAG}-1 + - run: | + cd .circleci/plugins/protoc-gen-openapiv2 && + docker build -t plugins.buf.build/grpc-ecosystem/openapiv2:${CIRCLE_TAG}-1 --build-arg=RELEASE_VERSION=${CIRCLE_TAG} . && + docker push plugins.buf.build/grpc-ecosystem/openapiv2:${CIRCLE_TAG}-1 + proto_lint: + docker: + - image: bufbuild/buf:1.1.0 + steps: + - checkout + - run: buf build + - run: buf lint + - run: buf breaking --path protoc-gen-openapiv2/ --against 'https://github.com/grpc-ecosystem/grpc-gateway.git#branch=master' + proto_push: + docker: + - image: bufbuild/buf:1.1.0 + steps: + - checkout + # Limit pushes to protoc-gen-openapiv2 files. This is a total hack. + # It excludes all the files that we don't want to publish, just for the push step. + - run: echo -e " - examples\n - internal\n - runtime" >> buf.yaml + - run: BUF_TOKEN="${BUF_API_TOKEN}" buf push --tag "$CIRCLE_SHA1" release: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - run: go mod vendor - run: curl -sL https://git.io/goreleaser | bash update-repositoriesbzl: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - restore_cache: keys: - - v2-bazel-cache-{{ checksum "repositories.bzl" }} - - v2-bazel-cache- + - v3-bazel-cache-{{ checksum "repositories.bzl" }} + - v3-bazel-cache- - configure_bazel - run: name: Update repositories.bzl @@ -176,7 +178,7 @@ jobs: - renovate_git_amend_push regenerate: executor: build-env - working_directory: /src/ease-gateway + working_directory: /home/vscode/src/ease-gateway steps: - checkout - generate @@ -187,18 +189,27 @@ workflows: jobs: - build - test - - fuzzit - node_test - generate - - lint - bazel - gorelease + - proto_lint + - proto_push: + filters: + branches: + only: /^master$/ - release: filters: branches: ignore: /.*/ tags: only: /v[0-9]+(\.[0-9]+)*(-.*)*/ + - push_bsr_plugins: + filters: + branches: + ignore: /.*/ + tags: + only: /v[0-9]+(\.[0-9]+)*(-.*)*/ - update-repositoriesbzl: filters: branches: @@ -215,4 +226,3 @@ workflows: only: /renovate\/master-.+/ tags: ignore: /.*/ - diff --git a/.circleci/plugins/protoc-gen-grpc-gateway/Dockerfile b/.circleci/plugins/protoc-gen-grpc-gateway/Dockerfile new file mode 100644 index 0000000..baf7d3a --- /dev/null +++ b/.circleci/plugins/protoc-gen-grpc-gateway/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:1.18.0 as builder + +ARG RELEASE_VERSION + +# Buf plugins must be built for linux/amd64 +ENV GOOS=linux GOARCH=amd64 CGO_ENABLED=0 +RUN go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@${RELEASE_VERSION} + +FROM scratch + +COPY --from=builder /go/bin/protoc-gen-grpc-gateway /usr/local/bin/protoc-gen-grpc-gateway + +ENTRYPOINT ["/usr/local/bin/protoc-gen-grpc-gateway"] diff --git a/.circleci/plugins/protoc-gen-openapiv2/Dockerfile b/.circleci/plugins/protoc-gen-openapiv2/Dockerfile new file mode 100644 index 0000000..2b9115e --- /dev/null +++ b/.circleci/plugins/protoc-gen-openapiv2/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:1.18.0 as builder + +ARG RELEASE_VERSION + +# Buf plugins must be built for linux/amd64 +ENV GOOS=linux GOARCH=amd64 CGO_ENABLED=0 +RUN go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@${RELEASE_VERSION} + +FROM scratch + +COPY --from=builder /go/bin/protoc-gen-openapiv2 /usr/local/bin/protoc-gen-openapiv2 + +ENTRYPOINT ["/usr/local/bin/protoc-gen-openapiv2"] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..0386e5f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "Go", + "build": { + "dockerfile": "../.circleci/Dockerfile", + "args": { + "NODE_VERSION": "10" + } + }, + "settings": { + "editor.formatOnSave": true, + "go.toolsManagement.checkForUpdates": "local", + "go.useLanguageServer": true, + "go.gopath": "/go", + "go.goroot": "/usr/local/go", + "bazel.buildifierExecutable": "/go/bin/buildifier", + "bazel.buildifierFixOnFormat": true, + "bazel.enableCodeLens": true, + }, + "extensions": [ + "golang.Go", + "bazelbuild.vscode-bazel", + ], + "remoteUser": "vscode" +} diff --git a/BUILD b/BUILD index 8d283d0..cf3996f 100644 --- a/BUILD +++ b/BUILD @@ -1,6 +1,9 @@ load("@bazel_gazelle//:def.bzl", "gazelle") load("@com_github_bazelbuild_buildtools//buildifier:def.bzl", "buildifier") load("@io_bazel_rules_go//proto:compiler.bzl", "go_proto_compiler") +load("@io_bazel_rules_go//proto/wkt:well_known_types.bzl", "PROTO_RUNTIME_DEPS", "WELL_KNOWN_TYPES_APIV2") + +exports_files(["LICENSE.txt"]) buildifier( name = "buildifier", @@ -11,11 +14,11 @@ buildifier( mode = "check", ) -# gazelle:exclude third_party # gazelle:exclude _output # gazelle:prefix github.com/binchencoder/ease-gateway/gateway # gazelle:go_proto_compilers //:go_apiv2 # gazelle:go_grpc_compilers //:go_apiv2, //:go_grpc +# gazelle:go_naming_convention import_alias gazelle(name = "gazelle") @@ -35,23 +38,7 @@ go_proto_compiler( plugin = "@org_golang_google_protobuf//cmd/protoc-gen-go", suffix = ".pb.go", visibility = ["//visibility:public"], - deps = [ - "@com_github_golang_protobuf//proto:go_default_library", - "@io_bazel_rules_go//proto/wkt:any_go_proto", - "@io_bazel_rules_go//proto/wkt:api_go_proto", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", - "@io_bazel_rules_go//proto/wkt:duration_go_proto", - "@io_bazel_rules_go//proto/wkt:empty_go_proto", - "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@io_bazel_rules_go//proto/wkt:source_context_go_proto", - "@io_bazel_rules_go//proto/wkt:struct_go_proto", - "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", - "@io_bazel_rules_go//proto/wkt:type_go_proto", - "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", - "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", - "@org_golang_google_protobuf//runtime/protoimpl:go_default_library", - ], + deps = PROTO_RUNTIME_DEPS + WELL_KNOWN_TYPES_APIV2, ) go_proto_compiler( @@ -63,19 +50,7 @@ go_proto_compiler( plugin = "@org_golang_google_grpc_cmd_protoc_gen_go_grpc//:protoc-gen-go-grpc", suffix = "_grpc.pb.go", visibility = ["//visibility:public"], - deps = [ - "@io_bazel_rules_go//proto/wkt:any_go_proto", - "@io_bazel_rules_go//proto/wkt:api_go_proto", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", - "@io_bazel_rules_go//proto/wkt:duration_go_proto", - "@io_bazel_rules_go//proto/wkt:empty_go_proto", - "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@io_bazel_rules_go//proto/wkt:source_context_go_proto", - "@io_bazel_rules_go//proto/wkt:struct_go_proto", - "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", - "@io_bazel_rules_go//proto/wkt:type_go_proto", - "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", + deps = PROTO_RUNTIME_DEPS + [ "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes:go_default_library", "@org_golang_google_grpc//status:go_default_library", diff --git a/WORKSPACE b/WORKSPACE index 8bf12d5..796ce44 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,13 +1,22 @@ workspace(name = "com_github_binchencoder_ease_gateway") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +# Define before rules_proto, otherwise we receive the version of com_google_protobuf from there +http_archive( + name = "com_google_protobuf", + sha256 = "3bd7828aa5af4b13b99c191e8b1e884ebfa9ad371b0ce264605d347f135d2568", + strip_prefix = "protobuf-3.19.4", + urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.19.4.tar.gz"], +) http_archive( name = "bazel_skylib", - sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c", + sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.3/bazel-skylib-1.0.3.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz", ], ) @@ -17,11 +26,11 @@ bazel_skylib_workspace() http_archive( name = "rules_proto", - sha256 = "602e7161d9195e50246177e7c55b2f39950a9cf7366f74ed5f22fd45750cd208", - strip_prefix = "rules_proto-97d8af4dc474595af3900dd85cb3a29ad28cc313", + sha256 = "66bfdf8782796239d3875d37e7de19b1d94301e8972b3cbd2446b332429b4df1", + strip_prefix = "rules_proto-4.0.0", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz", - "https://github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0.tar.gz", + "https://github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0.tar.gz", ], ) @@ -33,33 +42,41 @@ rules_proto_toolchains() http_archive( name = "io_bazel_rules_go", - sha256 = "d1ffd055969c8f8d431e2d439813e42326961d0942bdf734d2c95dc30c369566", + sha256 = "d6b2513456fe2229811da7eb67a444be7785f5323c6708b38d851d2b51e54d83", urls = [ - "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/v0.24.5/rules_go-v0.24.5.tar.gz", - "https://github.com/bazelbuild/rules_go/releases/download/v0.24.5/rules_go-v0.24.5.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.30.0/rules_go-v0.30.0.zip", + "https://github.com/bazelbuild/rules_go/releases/download/v0.30.0/rules_go-v0.30.0.zip", ], ) # ---------- bazel_gazelle ---------- # 一般来说都会使用gazelle工具来自动生成 BUILD 文件, 而不是手写. -http_archive( +# http_archive( +# name = "bazel_gazelle", +# sha256 = "b85f48fa105c4403326e9525ad2b2cc437babaa6e15a3fc0b1dbab0ab064bc7c", +# urls = [ +# "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", +# "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", +# ], +# ) + +# TODO: Revert https://github.com/grpc-ecosystem/grpc-gateway/pull/2578/commits/fb9b59be7f2408767657c83c5002bf700ac7c460 once +# https://github.com/bazelbuild/bazel-gazelle/pull/1194 is merged +git_repository( name = "bazel_gazelle", - sha256 = "b85f48fa105c4403326e9525ad2b2cc437babaa6e15a3fc0b1dbab0ab064bc7c", - urls = [ - "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", - "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", - ], + commit = "4a1aeae7cab962fd8088f42038d3a477cdca91a5", + remote = "https://github.com/johanbrandhorst/bazel-gazelle", + shallow_since = "1647116890 +0000", ) + # 从下载的扩展里载入 go_rules_dependencies go_register_toolchains 函数 load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") # 注册一堆常用依赖 如github.com/google/protobuf golang.org/x/net go_rules_dependencies() # 下载golang工具链 -go_register_toolchains() +go_register_toolchains(version = "1.17.2") load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") -# 加载gazelle依赖 -gazelle_dependencies() # Use gazelle to declare Go dependencies in Bazel. # gazelle:repository_macro repositories.bzl%go_repositories @@ -68,21 +85,12 @@ load("//:repositories.bzl", "go_repositories") go_repositories() -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") - -git_repository( - name = "com_google_protobuf", - commit = "09745575a923640154bcf307fba8aedff47f240a", - remote = "https://github.com/protocolbuffers/protobuf", - shallow_since = "1558721209 -0700", -) +# 加载gazelle依赖 +# This must be invoked after our explicit dependencies +# See https://github.com/bazelbuild/bazel-gazelle/issues/1115. +gazelle_dependencies() -# go_repository( -# name = "com_google_protobuf", -# importpath = "github.com/protocolbuffers/protobuf", -# sum = "h1:pNPOCD+Nm4NY0R6gdOpwOPpRGUjbPo9SO/UlD56lH+0=", -# version = "v3.8.0+incompatible", -# ) +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") @@ -91,9 +99,9 @@ protobuf_deps() # ---------- com_github_bazelbuild_buildtools ---------- http_archive( name = "com_github_bazelbuild_buildtools", - sha256 = "a02ba93b96a8151b5d8d3466580f6c1f7e77212c4eb181cba53eb2cae7752a23", - strip_prefix = "buildtools-3.5.0", - urls = ["https://github.com/bazelbuild/buildtools/archive/3.5.0.tar.gz"], + sha256 = "7f43df3cca7bb4ea443b4159edd7a204c8d771890a69a50a190dc9543760ca21", + strip_prefix = "buildtools-5.0.1", + urls = ["https://github.com/bazelbuild/buildtools/archive/5.0.1.tar.gz"], ) load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_dependencies") diff --git a/examples/internal/integration/BUILD.bazel b/examples/internal/integration/BUILD.bazel index 8a5085e..6931ba2 100644 --- a/examples/internal/integration/BUILD.bazel +++ b/examples/internal/integration/BUILD.bazel @@ -12,7 +12,7 @@ go_test( # "//examples/internal/proto/examplepb:unannotated_go_default_library", "//examples/internal/server:go_default_library", "//gateway/runtime:go_default_library", - "//httpoptions:go_default_library", + "//httpoptions", "@com_github_golang_glog//:go_default_library", "@com_github_google_go_cmp//cmp:go_default_library", "@go_googleapis//google/rpc:status_go_proto", diff --git a/examples/internal/proto/examplepb/BUILD.bazel b/examples/internal/proto/examplepb/BUILD.bazel index 2a1db92..16e18c5 100644 --- a/examples/internal/proto/examplepb/BUILD.bazel +++ b/examples/internal/proto/examplepb/BUILD.bazel @@ -28,6 +28,8 @@ package(default_visibility = ["//visibility:public"]) # gazelle:exclude wrappers_grpc.pb.go # gazelle:exclude unannotated_echo_service.pb.gw.go # gazelle:exclude unannotated_echo_service_grpc.pb.go +# gazelle:exclude visibility_rule_echo_service.pb.gw.go +# gazelle:exclude visibility_rule_echo_service_grpc.pb.go # gazelle:exclude openapi_merge_a.proto # gazelle:exclude openapi_merge_b.proto # gazelle:go_grpc_compilers //:go_apiv2, //:go_grpc, //protoc-gen-grpc-gateway:go_gen_grpc_gateway @@ -36,9 +38,10 @@ proto_library( name = "examplepb_proto", srcs = [ "echo_service.proto", - "unannotated_echo_service.proto", + # "unannotated_echo_service.proto", ], deps = [ + "//gateway/protoc-gen-openapiv2/options:options_proto", "//httpoptions:options_proto", "@com_github_binchencoder_gateway_proto//data:data_proto", "@com_github_binchencoder_gateway_proto//frontend:error_proto", @@ -50,17 +53,21 @@ proto_library( "@com_google_protobuf//:wrappers_proto", "@go_googleapis//google/api:annotations_proto", "@go_googleapis//google/api:httpbody_proto", + "@go_googleapis//google/api:visibility_proto", "@go_googleapis//google/rpc:status_proto", ], ) +#keep # proto_library( -# name = "examplepb_unannotated_proto", +# name = "openapi_merge_proto", # srcs = [ -# "unannotated_echo_service.proto", +# "openapi_merge_a.proto", +# "openapi_merge_b.proto", # ], # deps = [ -# "@com_google_protobuf//:duration_proto", +# "@go_googleapis//google/api:annotations_proto", +# "@go_googleapis//google/api:httpbody_proto", # ], # ) @@ -69,66 +76,50 @@ go_proto_library( compilers = [ "//:go_apiv2", "//:go_grpc", - "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep + "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", ], importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", proto = ":examplepb_proto", deps = [ - "//httpoptions:go_default_library", + "//httpoptions", "@com_github_binchencoder_letsgo//grpc:go_default_library", "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", "@com_github_binchencoder_skylb_api//client/option:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", + "//gateway/protoc-gen-openapiv2/options", "@com_github_golang_protobuf//descriptor:go_default_library_gen", # keep "@go_googleapis//google/api:annotations_go_proto", "@go_googleapis//google/api:httpbody_go_proto", + "@go_googleapis//google/api:visibility_go_proto", "@go_googleapis//google/rpc:status_go_proto", "@org_golang_google_protobuf//proto:go_default_library", # keep - "@org_golang_google_grpc//naming:go_default_library", + # "@org_golang_google_grpc//naming:go_default_library", ], ) -# go_proto_library( -# name = "examplepb_unannotated_go_proto", -# compilers = [ -# "//:go_apiv2", -# "//:go_grpc", -# "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep -# ], -# importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", -# proto = ":examplepb_unannotated_proto", -# deps = [ -# "//gateway/protoc-gen-openapiv2/options:go_default_library", -# "@com_github_golang_protobuf//descriptor:go_default_library_gen", # keep -# "@go_googleapis//google/api:annotations_go_proto", -# "@go_googleapis//google/api:httpbody_go_proto", -# "@go_googleapis//google/rpc:status_go_proto", -# "@org_golang_google_protobuf//proto:go_default_library", # keep -# ], -# ) - go_library( - name = "go_default_library", + name = "examplepb", embed = [":examplepb_go_proto"], importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", deps = [ - "//httpoptions:go_default_library", - "//gateway/runtime:go_default_library", - "@com_github_binchencoder_gateway_proto//data:go_default_library", + "//httpoptions", + "//gateway/runtime", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//codes", + "@org_golang_google_grpc//grpclog", + "@org_golang_google_grpc//metadata", + "@org_golang_google_grpc//status", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//reflect/protoreflect", + "@org_golang_google_protobuf//runtime/protoimpl", ], ) -# go_library( -# name = "unannotated_go_default_library", -# embed = [":examplepb_unannotated_go_proto"], -# importpath = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb", -# ) - protoc_gen_openapiv2( name = "examplepb_protoc_gen_openapiv2", proto = ":examplepb_proto", @@ -138,4 +129,16 @@ protoc_gen_openapiv2( name = "examplepb_protoc_gen_openapiv2_merged", proto = ":examplepb_proto", single_output = True, # Outputs a single swagger.json file. -) \ No newline at end of file +) + +# protoc_gen_openapiv2( +# name = "examplepb_openapi_merge", +# proto = ":openapi_merge_proto", +# single_output = True, # Outputs a single swagger.json file. +# ) + +alias( + name = "go_default_library", + actual = ":examplepb", + visibility = ["//examples:__subpackages__"], +) diff --git a/examples/internal/proto/examplepb/echo_service.pb.go b/examples/internal/proto/examplepb/echo_service.pb.go deleted file mode 100755 index 73bfcac..0000000 --- a/examples/internal/proto/examplepb/echo_service.pb.go +++ /dev/null @@ -1,758 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.25.0 -// protoc v3.9.0 -// source: examples/internal/proto/examplepb/echo_service.proto - -package examplepb - -import ( - _ "github.com/binchencoder/ease-gateway/httpoptions" - proto "github.com/golang/protobuf/proto" - _struct "github.com/golang/protobuf/ptypes/struct" - field_mask "google.golang.org/genproto/protobuf/field_mask" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -type Embedded struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Mark: - // *Embedded_Progress - // *Embedded_Note - Mark isEmbedded_Mark `protobuf_oneof:"mark"` -} - -func (x *Embedded) Reset() { - *x = Embedded{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Embedded) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Embedded) ProtoMessage() {} - -func (x *Embedded) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0] - 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 Embedded.ProtoReflect.Descriptor instead. -func (*Embedded) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{0} -} - -func (m *Embedded) GetMark() isEmbedded_Mark { - if m != nil { - return m.Mark - } - return nil -} - -func (x *Embedded) GetProgress() int64 { - if x, ok := x.GetMark().(*Embedded_Progress); ok { - return x.Progress - } - return 0 -} - -func (x *Embedded) GetNote() string { - if x, ok := x.GetMark().(*Embedded_Note); ok { - return x.Note - } - return "" -} - -type isEmbedded_Mark interface { - isEmbedded_Mark() -} - -type Embedded_Progress struct { - Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` -} - -type Embedded_Note struct { - Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` -} - -func (*Embedded_Progress) isEmbedded_Mark() {} - -func (*Embedded_Note) isEmbedded_Mark() {} - -type SimpleMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` - // Types that are assignable to Code: - // *SimpleMessage_LineNum - // *SimpleMessage_Lang - Code isSimpleMessage_Code `protobuf_oneof:"code"` - Status *Embedded `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - // Types that are assignable to Ext: - // *SimpleMessage_En - // *SimpleMessage_No - Ext isSimpleMessage_Ext `protobuf_oneof:"ext"` -} - -func (x *SimpleMessage) Reset() { - *x = SimpleMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SimpleMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SimpleMessage) ProtoMessage() {} - -func (x *SimpleMessage) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1] - 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 SimpleMessage.ProtoReflect.Descriptor instead. -func (*SimpleMessage) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{1} -} - -func (x *SimpleMessage) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *SimpleMessage) GetNum() int64 { - if x != nil { - return x.Num - } - return 0 -} - -func (m *SimpleMessage) GetCode() isSimpleMessage_Code { - if m != nil { - return m.Code - } - return nil -} - -func (x *SimpleMessage) GetLineNum() int64 { - if x, ok := x.GetCode().(*SimpleMessage_LineNum); ok { - return x.LineNum - } - return 0 -} - -func (x *SimpleMessage) GetLang() string { - if x, ok := x.GetCode().(*SimpleMessage_Lang); ok { - return x.Lang - } - return "" -} - -func (x *SimpleMessage) GetStatus() *Embedded { - if x != nil { - return x.Status - } - return nil -} - -func (m *SimpleMessage) GetExt() isSimpleMessage_Ext { - if m != nil { - return m.Ext - } - return nil -} - -func (x *SimpleMessage) GetEn() int64 { - if x, ok := x.GetExt().(*SimpleMessage_En); ok { - return x.En - } - return 0 -} - -func (x *SimpleMessage) GetNo() *Embedded { - if x, ok := x.GetExt().(*SimpleMessage_No); ok { - return x.No - } - return nil -} - -type isSimpleMessage_Code interface { - isSimpleMessage_Code() -} - -type SimpleMessage_LineNum struct { - LineNum int64 `protobuf:"varint,3,opt,name=line_num,json=lineNum,proto3,oneof"` -} - -type SimpleMessage_Lang struct { - Lang string `protobuf:"bytes,4,opt,name=lang,proto3,oneof"` -} - -func (*SimpleMessage_LineNum) isSimpleMessage_Code() {} - -func (*SimpleMessage_Lang) isSimpleMessage_Code() {} - -type isSimpleMessage_Ext interface { - isSimpleMessage_Ext() -} - -type SimpleMessage_En struct { - En int64 `protobuf:"varint,6,opt,name=en,proto3,oneof"` -} - -type SimpleMessage_No struct { - No *Embedded `protobuf:"bytes,7,opt,name=no,proto3,oneof"` -} - -func (*SimpleMessage_En) isSimpleMessage_Ext() {} - -func (*SimpleMessage_No) isSimpleMessage_Ext() {} - -type ValidationRuleTestRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` -} - -func (x *ValidationRuleTestRequest) Reset() { - *x = ValidationRuleTestRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ValidationRuleTestRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ValidationRuleTestRequest) ProtoMessage() {} - -func (x *ValidationRuleTestRequest) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2] - 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 ValidationRuleTestRequest.ProtoReflect.Descriptor instead. -func (*ValidationRuleTestRequest) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{2} -} - -func (x *ValidationRuleTestRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *ValidationRuleTestRequest) GetNum() int64 { - if x != nil { - return x.Num - } - return 0 -} - -type ValidationRuleTestResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *ValidationRuleTestResponse) Reset() { - *x = ValidationRuleTestResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ValidationRuleTestResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ValidationRuleTestResponse) ProtoMessage() {} - -func (x *ValidationRuleTestResponse) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3] - 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 ValidationRuleTestResponse.ProtoReflect.Descriptor instead. -func (*ValidationRuleTestResponse) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{3} -} - -type DynamicMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - StructField *_struct.Struct `protobuf:"bytes,1,opt,name=struct_field,json=structField,proto3" json:"struct_field,omitempty"` - ValueField *_struct.Value `protobuf:"bytes,2,opt,name=value_field,json=valueField,proto3" json:"value_field,omitempty"` -} - -func (x *DynamicMessage) Reset() { - *x = DynamicMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DynamicMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DynamicMessage) ProtoMessage() {} - -func (x *DynamicMessage) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4] - 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 DynamicMessage.ProtoReflect.Descriptor instead. -func (*DynamicMessage) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{4} -} - -func (x *DynamicMessage) GetStructField() *_struct.Struct { - if x != nil { - return x.StructField - } - return nil -} - -func (x *DynamicMessage) GetValueField() *_struct.Value { - if x != nil { - return x.ValueField - } - return nil -} - -type DynamicMessageUpdate struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Body *DynamicMessage `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` - UpdateMask *field_mask.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` -} - -func (x *DynamicMessageUpdate) Reset() { - *x = DynamicMessageUpdate{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DynamicMessageUpdate) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DynamicMessageUpdate) ProtoMessage() {} - -func (x *DynamicMessageUpdate) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_echo_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 DynamicMessageUpdate.ProtoReflect.Descriptor instead. -func (*DynamicMessageUpdate) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{5} -} - -func (x *DynamicMessageUpdate) GetBody() *DynamicMessage { - if x != nil { - return x.Body - } - return nil -} - -func (x *DynamicMessageUpdate) GetUpdateMask() *field_mask.FieldMask { - if x != nil { - return x.UpdateMask - } - return nil -} - -var File_examples_internal_proto_examplepb_echo_service_proto protoreflect.FileDescriptor - -var file_examples_internal_proto_examplepb_echo_service_proto_rawDesc = []byte{ - 0x0a, 0x34, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x70, 0x62, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 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, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, - 0x6b, 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, 0x46, 0x0a, 0x08, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, - 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xa3, 0x02, - 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6e, 0x75, - 0x6d, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, - 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, - 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x50, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x4a, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, - 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, - 0x65, 0x78, 0x74, 0x22, 0x6f, 0x0a, 0x19, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x31, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xb2, 0xe4, - 0x34, 0x1d, 0x0a, 0x04, 0x08, 0x05, 0x10, 0x02, 0x0a, 0x09, 0x08, 0x06, 0x10, 0x02, 0x1a, 0x01, - 0x32, 0x20, 0x01, 0x0a, 0x0a, 0x08, 0x07, 0x10, 0x02, 0x1a, 0x02, 0x36, 0x31, 0x20, 0x01, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x42, 0x0d, 0xb2, 0xe4, 0x34, 0x09, 0x0a, 0x07, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x01, 0x30, 0x52, - 0x03, 0x6e, 0x75, 0x6d, 0x22, 0x1c, 0x0a, 0x1a, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x0e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, - 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, - 0x64, 0x12, 0x37, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x22, 0xa7, 0x01, 0x0a, 0x14, 0x44, - 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x12, 0x52, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x70, 0x62, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x4d, 0x61, 0x73, 0x6b, 0x32, 0xd5, 0x08, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0xba, 0x02, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x3d, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, - 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, - 0x34, 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, - 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, - 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, - 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, - 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, - 0x31, 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, - 0x63, 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, - 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, - 0x65, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, - 0x7d, 0x12, 0xa8, 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x3d, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, - 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1e, 0xca, 0xf3, - 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, - 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0xa9, 0x01, 0x0a, - 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x3d, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x6d, - 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, 0x67, 0x72, 0x70, - 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x6d, 0x70, - 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0xca, 0xf3, 0x34, 0x19, 0x2a, - 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, - 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0xbb, 0x01, 0x0a, 0x09, 0x45, 0x63, 0x68, - 0x6f, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12, 0x44, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x44, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x44, 0x79, - 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x22, 0x22, 0xca, 0xf3, 0x34, 0x1e, 0x32, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, - 0x3a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0xd6, 0x01, 0x0a, 0x12, 0x45, 0x63, 0x68, 0x6f, 0x56, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x49, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x56, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x4a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0xca, 0xf3, 0x34, 0x25, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x3a, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x1a, - 0x1b, 0xea, 0xf3, 0x34, 0x17, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, - 0x63, 0x1a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x52, 0x5a, 0x50, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, - 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_examples_internal_proto_examplepb_echo_service_proto_rawDescOnce sync.Once - file_examples_internal_proto_examplepb_echo_service_proto_rawDescData = file_examples_internal_proto_examplepb_echo_service_proto_rawDesc -) - -func file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP() []byte { - file_examples_internal_proto_examplepb_echo_service_proto_rawDescOnce.Do(func() { - file_examples_internal_proto_examplepb_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_internal_proto_examplepb_echo_service_proto_rawDescData) - }) - return file_examples_internal_proto_examplepb_echo_service_proto_rawDescData -} - -var file_examples_internal_proto_examplepb_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_examples_internal_proto_examplepb_echo_service_proto_goTypes = []interface{}{ - (*Embedded)(nil), // 0: grpc.gateway.examples.internal.proto.examplepb.Embedded - (*SimpleMessage)(nil), // 1: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - (*ValidationRuleTestRequest)(nil), // 2: grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestRequest - (*ValidationRuleTestResponse)(nil), // 3: grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestResponse - (*DynamicMessage)(nil), // 4: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage - (*DynamicMessageUpdate)(nil), // 5: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate - (*_struct.Struct)(nil), // 6: google.protobuf.Struct - (*_struct.Value)(nil), // 7: google.protobuf.Value - (*field_mask.FieldMask)(nil), // 8: google.protobuf.FieldMask -} -var file_examples_internal_proto_examplepb_echo_service_proto_depIdxs = []int32{ - 0, // 0: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.Embedded - 0, // 1: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.Embedded - 6, // 2: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage.struct_field:type_name -> google.protobuf.Struct - 7, // 3: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage.value_field:type_name -> google.protobuf.Value - 4, // 4: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate.body:type_name -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessage - 8, // 5: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate.update_mask:type_name -> google.protobuf.FieldMask - 1, // 6: grpc.gateway.examples.internal.proto.examplepb.EchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 1, // 7: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 1, // 8: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 5, // 9: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoPatch:input_type -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate - 2, // 10: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoValidationRule:input_type -> grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestRequest - 1, // 11: grpc.gateway.examples.internal.proto.examplepb.EchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 1, // 12: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 1, // 13: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage - 5, // 14: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoPatch:output_type -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate - 3, // 15: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoValidationRule:output_type -> grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestResponse - 11, // [11:16] is the sub-list for method output_type - 6, // [6:11] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name -} - -func init() { file_examples_internal_proto_examplepb_echo_service_proto_init() } -func file_examples_internal_proto_examplepb_echo_service_proto_init() { - if File_examples_internal_proto_examplepb_echo_service_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Embedded); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SimpleMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ValidationRuleTestRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ValidationRuleTestResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DynamicMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DynamicMessageUpdate); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ - (*Embedded_Progress)(nil), - (*Embedded_Note)(nil), - } - file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ - (*SimpleMessage_LineNum)(nil), - (*SimpleMessage_Lang)(nil), - (*SimpleMessage_En)(nil), - (*SimpleMessage_No)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_examples_internal_proto_examplepb_echo_service_proto_rawDesc, - NumEnums: 0, - NumMessages: 6, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_examples_internal_proto_examplepb_echo_service_proto_goTypes, - DependencyIndexes: file_examples_internal_proto_examplepb_echo_service_proto_depIdxs, - MessageInfos: file_examples_internal_proto_examplepb_echo_service_proto_msgTypes, - }.Build() - File_examples_internal_proto_examplepb_echo_service_proto = out.File - file_examples_internal_proto_examplepb_echo_service_proto_rawDesc = nil - file_examples_internal_proto_examplepb_echo_service_proto_goTypes = nil - file_examples_internal_proto_examplepb_echo_service_proto_depIdxs = nil -} diff --git a/examples/internal/proto/examplepb/echo_service.pb.gw.go b/examples/internal/proto/examplepb/echo_service.pb.gw.go deleted file mode 100755 index 7b6896c..0000000 --- a/examples/internal/proto/examplepb/echo_service.pb.gw.go +++ /dev/null @@ -1,1522 +0,0 @@ -// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: examples/internal/proto/examplepb/echo_service.proto - -/* -Package examplepb is a reverse proxy. - -It translates gRPC into RESTful JSON APIs. -*/ -package examplepb - -import ( - "context" - "io" - "net/http" - "regexp" - "strings" - "sync" - "unicode/utf8" - - "github.com/binchencoder/ease-gateway/gateway/runtime" - vexpb "github.com/binchencoder/gateway-proto/data" - fpb "github.com/binchencoder/gateway-proto/frontend" - lgr "github.com/binchencoder/letsgo/grpc" - "github.com/binchencoder/skylb-api/balancer" - "github.com/binchencoder/skylb-api/client" - "github.com/binchencoder/skylb-api/client/option" - skypb "github.com/binchencoder/skylb-api/proto" - "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/naming" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" -) - -// Suppress "imported and not used" errors -var _ codes.Code -var _ io.Reader -var _ status.Status -var _ = runtime.String -var _ = utilities.NewDoubleArray - -// var _ = descriptor.ForMessage -var _ sync.RWMutex -var _ proto.Message -var _ context.Context -var _ grpc.ClientConn -var _ client.ServiceCli -var _ vexpb.ServiceId -var _ = http.MethodGet -var _ regexp.Regexp -var _ = balancer.ConsistentHashing -var _ option.BalancerCreator -var _ naming.Resolver -var _ strings.Reader -var _ = utf8.UTFMax - -// TODO (jiezmo): check if there is any rule before create this var. -var examples_internal_proto_examplepb_echo_service_error = lgr.ToGrpcError(codes.InvalidArgument, &fpb.Error{Code: fpb.ErrorCode_BADPARAM_ERROR, Params: []string{"Validation error"}}) - -// Validation methods start - -func Validate__grpc_gateway_examples_internal_proto_examplepb_ValidationRuleTestRequest(v *ValidationRuleTestRequest) error { - if v == nil { - return nil - } - // Validation for each Fields - - { - vv2 := v.Id - - // Validation Field: Id - - // TODO(jiezmo): fail the build - // Err - - if utf8.RuneCountInString(strings.TrimSpace(vv2)) <= 2 { - return examples_internal_proto_examplepb_echo_service_error - } - - if utf8.RuneCountInString(strings.TrimSpace(vv2)) >= 61 { - return examples_internal_proto_examplepb_echo_service_error - } - - } - - { - vv2 := v.Num - - // Validation Field: Num - - if vv2 <= 0 { - return examples_internal_proto_examplepb_echo_service_error - } - - } - - return nil -} - -// Validation methods done - -var ( - filter_EchoService_Echo_0 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} -) - -func request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "Echo", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Echo(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_Echo_1 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0, "num": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} -) - -func request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["num"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "num") - } - - protoReq.Num, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_1); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "Echo", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["num"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "num") - } - - protoReq.Num, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_1); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Echo(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_Echo_2 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0, "num": 1, "lang": 2}, Base: []int{1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 1, 1, 2, 3, 4}} -) - -func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["num"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "num") - } - - protoReq.Num, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) - } - - val, ok = pathParams["lang"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "lang") - } - - if protoReq.Code == nil { - protoReq.Code = &SimpleMessage_Lang{} - } else if _, ok := protoReq.Code.(*SimpleMessage_Lang); !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) - } - protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lang", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_2); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "Echo", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["num"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "num") - } - - protoReq.Num, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "num", err) - } - - val, ok = pathParams["lang"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "lang") - } - - if protoReq.Code == nil { - protoReq.Code = &SimpleMessage_Lang{} - } else if _, ok := protoReq.Code.(*SimpleMessage_Lang); !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_Lang, but: %t\n", protoReq.Code) - } - protoReq.Code.(*SimpleMessage_Lang).Lang, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "lang", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_2); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Echo(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_Echo_3 = &utilities.DoubleArray{Encoding: map[string]int{"id": 0, "line_num": 1, "status": 2, "note": 3}, Base: []int{1, 1, 2, 1, 3, 0, 0, 0}, Check: []int{0, 1, 1, 1, 4, 2, 3, 5}} -) - -func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["line_num"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "line_num") - } - - if protoReq.Code == nil { - protoReq.Code = &SimpleMessage_LineNum{} - } else if _, ok := protoReq.Code.(*SimpleMessage_LineNum); !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) - } - protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "line_num", err) - } - - val, ok = pathParams["status.note"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "status.note") - } - - err = runtime.PopulateFieldFromPath(&protoReq, "status.note", val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "status.note", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_3); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "Echo", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["id"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") - } - - protoReq.Id, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) - } - - val, ok = pathParams["line_num"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "line_num") - } - - if protoReq.Code == nil { - protoReq.Code = &SimpleMessage_LineNum{} - } else if _, ok := protoReq.Code.(*SimpleMessage_LineNum); !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "expect type: *SimpleMessage_LineNum, but: %t\n", protoReq.Code) - } - protoReq.Code.(*SimpleMessage_LineNum).LineNum, err = runtime.Int64(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "line_num", err) - } - - val, ok = pathParams["status.note"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "status.note") - } - - err = runtime.PopulateFieldFromPath(&protoReq, "status.note", val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "status.note", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_3); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Echo(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_Echo_4 = &utilities.DoubleArray{Encoding: map[string]int{"no": 0, "note": 1}, Base: []int{1, 1, 1, 0}, Check: []int{0, 1, 2, 3}} -) - -func request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["no.note"] - if !ok { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "no.note") - } - - err = runtime.PopulateFieldFromPath(&protoReq, "no.note", val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "no.note", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_4); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "Echo", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["no.note"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "no.note") - } - - err = runtime.PopulateFieldFromPath(&protoReq, "no.note", val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "no.note", err) - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_Echo_4); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.Echo(ctx, &protoReq) - return msg, metadata, err - -} - -func request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - 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 { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoBody", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "EchoBody", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.EchoBody(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "EchoBody", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "EchoBody", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - 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 { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.EchoBody(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_EchoDelete_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - -func request_EchoService_EchoDelete_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoDelete_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "EchoDelete", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.EchoDelete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "EchoDelete", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "EchoDelete", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_EchoDelete_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq SimpleMessage - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoDelete_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.EchoDelete(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_EchoService_EchoPatch_0 = &utilities.DoubleArray{Encoding: map[string]int{"body": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} -) - -func request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq DynamicMessageUpdate - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - 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.Body); err != nil && err != io.EOF { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoPatch", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { - if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Body); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } else { - protoReq.UpdateMask = fieldMask - } - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoPatch_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - runtime.RequestParsed(ctx, spec, "EchoService", "EchoPatch", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.EchoPatch(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "EchoPatch", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "EchoPatch", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq DynamicMessageUpdate - 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.Body); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { - if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Body); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } else { - protoReq.UpdateMask = fieldMask - } - } - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoPatch_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.EchoPatch(ctx, &protoReq) - return msg, metadata, err - -} - -func request_EchoService_EchoValidationRule_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidationRuleTestRequest - var metadata runtime.ServerMetadata - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - 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 { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", nil, &metadata, err) - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - // Only hook up for non-stream call for now. - - // Validate - // ValidationRuleTestRequest - if err := Validate__grpc_gateway_examples_internal_proto_examplepb_ValidationRuleTestRequest(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", nil, &metadata, err) - return nil, metadata, err - } - - runtime.RequestParsed(ctx, spec, "EchoService", "EchoValidationRule", &protoReq, &metadata) - ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) - msg, err := client.EchoValidationRule(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - // if err != nil { - // grpclog.Errorf("client.%s returns error: %v", "EchoValidationRule", err) - // } - runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", msg, &metadata, err) - return msg, metadata, err - -} - -func local_request_EchoService_EchoValidationRule_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ValidationRuleTestRequest - 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 { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.EchoValidationRule(ctx, &protoReq) - return msg, metadata, err - -} - -// RegisterEchoServiceHandlerServer registers the http handlers for service EchoService to "mux". -// UnaryRPC :call EchoServiceServer directly. -// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterEchoServiceHandlerFromEndpoint instead. -func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server EchoServiceServer) error { - - mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_Echo_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_Echo_1(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_Echo_2(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_2(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_Echo_3(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_3(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_Echo_4(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_4(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_EchoBody_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoBody_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_EchoDelete_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoDelete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_EchoPatch_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoPatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_EchoService_EchoValidationRule_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoValidationRule_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -// Register itself to runtime. -func init() { - var s *runtime.Service - var spec *skypb.ServiceSpec - - _ = s - _ = spec - - spec = internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - s = &runtime.Service{ - Spec: *spec, - Name: "EchoService", - Register: RegisterEchoServiceHandlerFromEndpoint, - Enable: EnableEchoService_Service, - Disable: DisableEchoService_Service, - } - - runtime.AddService(s, Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup, Disable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup) - -} - -// RegisterEchoServiceHandlerFromEndpoint is same as RegisterEchoServiceHandler but -// automatically dials to "endpoint" and closes the connection when "ctx" gets done. -func RegisterEchoServiceHandlerFromEndpoint(mux *runtime.ServeMux) (err error) { - // conn, err := grpc.Dial(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) - // } - // return - // } - // go func() { - // <-ctx.Done() - // if cerr := conn.Close(); cerr != nil { - // grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - // } - // }() - // }() - - // return RegisterEchoServiceHandler(ctx, mux, conn) - return RegisterEchoServiceHandler(nil, mux, nil) -} - -// RegisterEchoServiceHandler registers the http handlers for service EchoService to "mux". -// The handlers forward requests to the grpc endpoint over "conn". -func RegisterEchoServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - return RegisterEchoServiceHandlerClient(ctx, mux, NewEchoServiceClient(conn)) -} - -// RegisterEchoServiceHandlerClient registers the http handlers for service EchoService -// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "EchoServiceClient". -// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "EchoServiceClient" -// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "EchoServiceClient" to call the correct interceptors. -func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client EchoServiceClient) error { - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_Echo_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}/{num}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_Echo_1(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo/{id}/{num}/{lang}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_Echo_2(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_2(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo1/{id}/{line_num}/{status.note}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_Echo_3(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_3(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "Echo", "/v1/example/echo2/{no.note}", "GET", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "Echo", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_Echo_4(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_Echo_4(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "EchoBody", "/v1/example/echo_body", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoBody", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_EchoBody_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoBody_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "EchoDelete", "/v1/example/echo_delete", "DELETE", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoDelete", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_EchoDelete_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoDelete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "EchoPatch", "/v1/example/echo_patch", "PATCH", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoPatch", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_EchoPatch_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoPatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - runtime.AddMethod(spec, "EchoService", "EchoValidationRule", "/v1/example/echo:validationRules", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") - mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - // TODO(mojz): review all locking/unlocking logic. - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() - client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - if client == nil { - err := status.Error(codes.Internal, "service disabled") - runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) - return - } - - ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoValidationRule", w, req) - if err != nil { - grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule") - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_EchoService_EchoValidationRule_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_EchoService_EchoValidationRule_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -func Disable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() { - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Lock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Unlock() - if internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli != nil { - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - sg := runtime.GetServiceGroup(spec) - for _, svc := range sg.Services { - svc.Disable() - } - - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client = nil - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Shutdown() - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli = nil - } -} - -func Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() { - // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Lock() - // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.Unlock() - - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli = client.NewServiceCli(runtime.CallerServiceId) - - // Resolve service - spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec - - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Resolve(spec) - - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.EnableResolveFullEps() - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Start(func(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { - sg := runtime.GetServiceGroup(spec) - for _, svc := range sg.Services { - svc.Enable(spec, conn) - } - }) -} - -func EnableEchoService_Service(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client = NewEchoServiceClient(conn) -} - -func DisableEchoService_Service() { - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client = nil -} - -var ( - pattern_EchoService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo", "id"}, "")) - - pattern_EchoService_Echo_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "example", "echo", "id", "num"}, "")) - - pattern_EchoService_Echo_2 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo", "id", "num", "lang"}, "")) - - pattern_EchoService_Echo_3 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"v1", "example", "echo1", "id", "line_num", "status.note"}, "")) - - pattern_EchoService_Echo_4 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo2", "no.note"}, "")) - - pattern_EchoService_EchoBody_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_body"}, "")) - - pattern_EchoService_EchoDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_delete"}, "")) - - pattern_EchoService_EchoPatch_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_patch"}, "")) - - pattern_EchoService_EchoValidationRule_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo"}, "validationRules")) -) - -var ( - forward_EchoService_Echo_0 = runtime.ForwardResponseMessage - - forward_EchoService_Echo_1 = runtime.ForwardResponseMessage - - forward_EchoService_Echo_2 = runtime.ForwardResponseMessage - - forward_EchoService_Echo_3 = runtime.ForwardResponseMessage - - forward_EchoService_Echo_4 = runtime.ForwardResponseMessage - - forward_EchoService_EchoBody_0 = runtime.ForwardResponseMessage - - forward_EchoService_EchoDelete_0 = runtime.ForwardResponseMessage - - forward_EchoService_EchoPatch_0 = runtime.ForwardResponseMessage - - forward_EchoService_EchoValidationRule_0 = runtime.ForwardResponseMessage -) - -var ( - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec = client.NewServiceSpec("default", vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc") - internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client EchoServiceClient - - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli client.ServiceCli - - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock = sync.RWMutex{} -) diff --git a/examples/internal/proto/examplepb/echo_service_grpc.pb.go b/examples/internal/proto/examplepb/echo_service_grpc.pb.go deleted file mode 100755 index ef29065..0000000 --- a/examples/internal/proto/examplepb/echo_service_grpc.pb.go +++ /dev/null @@ -1,230 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. - -package examplepb - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 - -// EchoServiceClient is the client API for EchoService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type EchoServiceClient interface { - Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) - EchoValidationRule(ctx context.Context, in *ValidationRuleTestRequest, opts ...grpc.CallOption) (*ValidationRuleTestResponse, error) -} - -type echoServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { - return &echoServiceClient{cc} -} - -func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) { - out := new(DynamicMessageUpdate) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoValidationRule(ctx context.Context, in *ValidationRuleTestRequest, opts ...grpc.CallOption) (*ValidationRuleTestResponse, error) { - out := new(ValidationRuleTestResponse) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// EchoServiceServer is the server API for EchoService service. -type EchoServiceServer interface { - Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) - EchoValidationRule(context.Context, *ValidationRuleTestRequest) (*ValidationRuleTestResponse, error) -} - -// UnimplementedEchoServiceServer can be embedded to have forward compatible implementations. -type UnimplementedEchoServiceServer struct { -} - -func (*UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") -} -func (*UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") -} -func (*UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") -} -func (*UnimplementedEchoServiceServer) EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoPatch not implemented") -} -func (*UnimplementedEchoServiceServer) EchoValidationRule(context.Context, *ValidationRuleTestRequest) (*ValidationRuleTestResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoValidationRule not implemented") -} - -func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { - s.RegisterService(&_EchoService_serviceDesc, srv) -} - -func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).Echo(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoBody(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoDelete(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoPatch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(DynamicMessageUpdate) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoPatch(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoPatch(ctx, req.(*DynamicMessageUpdate)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoValidationRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ValidationRuleTestRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoValidationRule(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoValidationRule(ctx, req.(*ValidationRuleTestRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _EchoService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "grpc.gateway.examples.internal.proto.examplepb.EchoService", - HandlerType: (*EchoServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Echo", - Handler: _EchoService_Echo_Handler, - }, - { - MethodName: "EchoBody", - Handler: _EchoService_EchoBody_Handler, - }, - { - MethodName: "EchoDelete", - Handler: _EchoService_EchoDelete_Handler, - }, - { - MethodName: "EchoPatch", - Handler: _EchoService_EchoPatch_Handler, - }, - { - MethodName: "EchoValidationRule", - Handler: _EchoService_EchoValidationRule_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "examples/internal/proto/examplepb/echo_service.proto", -} diff --git a/examples/internal/proto/examplepb/standalone_echo_service.yaml b/examples/internal/proto/examplepb/standalone_echo_service.yaml index 3d45a4c..fbd9192 100644 --- a/examples/internal/proto/examplepb/standalone_echo_service.yaml +++ b/examples/internal/proto/examplepb/standalone_echo_service.yaml @@ -1,4 +1,4 @@ -type: goole.api.Service +type: google.api.Service config_version: 3 http: diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go deleted file mode 100644 index 4b6663b..0000000 --- a/examples/internal/proto/examplepb/unannotated_echo_service.pb.go +++ /dev/null @@ -1,616 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 -// source: examples/internal/proto/examplepb/unannotated_echo_service.proto - -// Unannotated Echo Service -// Similar to echo_service.proto but without annotations. See -// unannotated_echo_service.yaml for the equivalent of the annotations in -// gRPC API configuration format. -// -// Echo Service API consists of a single service which returns -// a message. - -package examplepb - -import ( - context "context" - proto "github.com/golang/protobuf/proto" - duration "github.com/golang/protobuf/ptypes/duration" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -// Embedded represents a message embedded in SimpleMessage. -type UnannotatedEmbedded struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Mark: - // *UnannotatedEmbedded_Progress - // *UnannotatedEmbedded_Note - Mark isUnannotatedEmbedded_Mark `protobuf_oneof:"mark"` -} - -func (x *UnannotatedEmbedded) Reset() { - *x = UnannotatedEmbedded{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UnannotatedEmbedded) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UnannotatedEmbedded) ProtoMessage() {} - -func (x *UnannotatedEmbedded) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0] - 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 UnannotatedEmbedded.ProtoReflect.Descriptor instead. -func (*UnannotatedEmbedded) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP(), []int{0} -} - -func (m *UnannotatedEmbedded) GetMark() isUnannotatedEmbedded_Mark { - if m != nil { - return m.Mark - } - return nil -} - -func (x *UnannotatedEmbedded) GetProgress() int64 { - if x, ok := x.GetMark().(*UnannotatedEmbedded_Progress); ok { - return x.Progress - } - return 0 -} - -func (x *UnannotatedEmbedded) GetNote() string { - if x, ok := x.GetMark().(*UnannotatedEmbedded_Note); ok { - return x.Note - } - return "" -} - -type isUnannotatedEmbedded_Mark interface { - isUnannotatedEmbedded_Mark() -} - -type UnannotatedEmbedded_Progress struct { - Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` -} - -type UnannotatedEmbedded_Note struct { - Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` -} - -func (*UnannotatedEmbedded_Progress) isUnannotatedEmbedded_Mark() {} - -func (*UnannotatedEmbedded_Note) isUnannotatedEmbedded_Mark() {} - -// UnannotatedSimpleMessage represents a simple message sent to the unannotated Echo service. -type UnannotatedSimpleMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Id represents the message identifier. - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` - Duration *duration.Duration `protobuf:"bytes,3,opt,name=duration,proto3" json:"duration,omitempty"` - // Types that are assignable to Code: - // *UnannotatedSimpleMessage_LineNum - // *UnannotatedSimpleMessage_Lang - Code isUnannotatedSimpleMessage_Code `protobuf_oneof:"code"` - Status *UnannotatedEmbedded `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` - // Types that are assignable to Ext: - // *UnannotatedSimpleMessage_En - // *UnannotatedSimpleMessage_No - Ext isUnannotatedSimpleMessage_Ext `protobuf_oneof:"ext"` -} - -func (x *UnannotatedSimpleMessage) Reset() { - *x = UnannotatedSimpleMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UnannotatedSimpleMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UnannotatedSimpleMessage) ProtoMessage() {} - -func (x *UnannotatedSimpleMessage) ProtoReflect() protoreflect.Message { - mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1] - 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 UnannotatedSimpleMessage.ProtoReflect.Descriptor instead. -func (*UnannotatedSimpleMessage) Descriptor() ([]byte, []int) { - return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP(), []int{1} -} - -func (x *UnannotatedSimpleMessage) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *UnannotatedSimpleMessage) GetNum() int64 { - if x != nil { - return x.Num - } - return 0 -} - -func (x *UnannotatedSimpleMessage) GetDuration() *duration.Duration { - if x != nil { - return x.Duration - } - return nil -} - -func (m *UnannotatedSimpleMessage) GetCode() isUnannotatedSimpleMessage_Code { - if m != nil { - return m.Code - } - return nil -} - -func (x *UnannotatedSimpleMessage) GetLineNum() int64 { - if x, ok := x.GetCode().(*UnannotatedSimpleMessage_LineNum); ok { - return x.LineNum - } - return 0 -} - -func (x *UnannotatedSimpleMessage) GetLang() string { - if x, ok := x.GetCode().(*UnannotatedSimpleMessage_Lang); ok { - return x.Lang - } - return "" -} - -func (x *UnannotatedSimpleMessage) GetStatus() *UnannotatedEmbedded { - if x != nil { - return x.Status - } - return nil -} - -func (m *UnannotatedSimpleMessage) GetExt() isUnannotatedSimpleMessage_Ext { - if m != nil { - return m.Ext - } - return nil -} - -func (x *UnannotatedSimpleMessage) GetEn() int64 { - if x, ok := x.GetExt().(*UnannotatedSimpleMessage_En); ok { - return x.En - } - return 0 -} - -func (x *UnannotatedSimpleMessage) GetNo() *UnannotatedEmbedded { - if x, ok := x.GetExt().(*UnannotatedSimpleMessage_No); ok { - return x.No - } - return nil -} - -type isUnannotatedSimpleMessage_Code interface { - isUnannotatedSimpleMessage_Code() -} - -type UnannotatedSimpleMessage_LineNum struct { - LineNum int64 `protobuf:"varint,4,opt,name=line_num,json=lineNum,proto3,oneof"` -} - -type UnannotatedSimpleMessage_Lang struct { - Lang string `protobuf:"bytes,5,opt,name=lang,proto3,oneof"` -} - -func (*UnannotatedSimpleMessage_LineNum) isUnannotatedSimpleMessage_Code() {} - -func (*UnannotatedSimpleMessage_Lang) isUnannotatedSimpleMessage_Code() {} - -type isUnannotatedSimpleMessage_Ext interface { - isUnannotatedSimpleMessage_Ext() -} - -type UnannotatedSimpleMessage_En struct { - En int64 `protobuf:"varint,7,opt,name=en,proto3,oneof"` -} - -type UnannotatedSimpleMessage_No struct { - No *UnannotatedEmbedded `protobuf:"bytes,8,opt,name=no,proto3,oneof"` -} - -func (*UnannotatedSimpleMessage_En) isUnannotatedSimpleMessage_Ext() {} - -func (*UnannotatedSimpleMessage_No) isUnannotatedSimpleMessage_Ext() {} - -var File_examples_internal_proto_examplepb_unannotated_echo_service_proto protoreflect.FileDescriptor - -var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc = []byte{ - 0x0a, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x70, 0x62, 0x2f, 0x75, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x70, 0x62, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0x51, 0x0a, 0x13, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, - 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, - 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, - 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, - 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xfb, 0x02, 0x0a, 0x18, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, - 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x08, 0x6c, - 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, - 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x5b, - 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, - 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, - 0x64, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, - 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x55, 0x0a, - 0x02, 0x6e, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, - 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, - 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, - 0x65, 0x78, 0x74, 0x32, 0xf9, 0x03, 0x0a, 0x16, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, - 0x74, 0x65, 0x64, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x9a, - 0x01, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, - 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, - 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x9e, 0x01, 0x0a, 0x08, - 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, - 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0xa0, 0x01, 0x0a, - 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x48, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, - 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, - 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, - 0x52, 0x5a, 0x50, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, - 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescOnce sync.Once - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData = file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc -) - -func file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP() []byte { - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescOnce.Do(func() { - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData) - }) - return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData -} - -var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes = []interface{}{ - (*UnannotatedEmbedded)(nil), // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded - (*UnannotatedSimpleMessage)(nil), // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - (*duration.Duration)(nil), // 2: google.protobuf.Duration -} -var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs = []int32{ - 2, // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.duration:type_name -> google.protobuf.Duration - 0, // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded - 0, // 2: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded - 1, // 3: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 4: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 5: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 6: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 7: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 1, // 8: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage - 6, // [6:9] is the sub-list for method output_type - 3, // [3:6] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name -} - -func init() { file_examples_internal_proto_examplepb_unannotated_echo_service_proto_init() } -func file_examples_internal_proto_examplepb_unannotated_echo_service_proto_init() { - if File_examples_internal_proto_examplepb_unannotated_echo_service_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnannotatedEmbedded); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnannotatedSimpleMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ - (*UnannotatedEmbedded_Progress)(nil), - (*UnannotatedEmbedded_Note)(nil), - } - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ - (*UnannotatedSimpleMessage_LineNum)(nil), - (*UnannotatedSimpleMessage_Lang)(nil), - (*UnannotatedSimpleMessage_En)(nil), - (*UnannotatedSimpleMessage_No)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes, - DependencyIndexes: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs, - MessageInfos: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes, - }.Build() - File_examples_internal_proto_examplepb_unannotated_echo_service_proto = out.File - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc = nil - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes = nil - file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs = nil -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConnInterface - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 - -// UnannotatedEchoServiceClient is the client API for UnannotatedEchoService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type UnannotatedEchoServiceClient interface { - // Echo method receives a simple message and returns it. - // - // The message posted as the id parameter will also be - // returned. - Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) - // EchoBody method receives a simple message and returns it. - EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) - // EchoDelete method receives a simple message and returns it. - EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) -} - -type unannotatedEchoServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewUnannotatedEchoServiceClient(cc grpc.ClientConnInterface) UnannotatedEchoServiceClient { - return &unannotatedEchoServiceClient{cc} -} - -func (c *unannotatedEchoServiceClient) Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *unannotatedEchoServiceClient) EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *unannotatedEchoServiceClient) EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// UnannotatedEchoServiceServer is the server API for UnannotatedEchoService service. -type UnannotatedEchoServiceServer interface { - // Echo method receives a simple message and returns it. - // - // The message posted as the id parameter will also be - // returned. - Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) - // EchoBody method receives a simple message and returns it. - EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) - // EchoDelete method receives a simple message and returns it. - EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) -} - -// UnimplementedUnannotatedEchoServiceServer can be embedded to have forward compatible implementations. -type UnimplementedUnannotatedEchoServiceServer struct { -} - -func (*UnimplementedUnannotatedEchoServiceServer) Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") -} -func (*UnimplementedUnannotatedEchoServiceServer) EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") -} -func (*UnimplementedUnannotatedEchoServiceServer) EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") -} - -func RegisterUnannotatedEchoServiceServer(s *grpc.Server, srv UnannotatedEchoServiceServer) { - s.RegisterService(&_UnannotatedEchoService_serviceDesc, srv) -} - -func _UnannotatedEchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).Echo(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).Echo(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _UnannotatedEchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _UnannotatedEchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -var _UnannotatedEchoService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService", - HandlerType: (*UnannotatedEchoServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Echo", - Handler: _UnannotatedEchoService_Echo_Handler, - }, - { - MethodName: "EchoBody", - Handler: _UnannotatedEchoService_EchoBody_Handler, - }, - { - MethodName: "EchoDelete", - Handler: _UnannotatedEchoService_EchoDelete_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "examples/internal/proto/examplepb/unannotated_echo_service.proto", -} diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go deleted file mode 100755 index b76fb60..0000000 --- a/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go +++ /dev/null @@ -1,3 +0,0 @@ -// +build ignore - -package ignore \ No newline at end of file diff --git a/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go deleted file mode 100755 index 0b0c944..0000000 --- a/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go +++ /dev/null @@ -1,158 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. - -package examplepb - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 - -// UnannotatedEchoServiceClient is the client API for UnannotatedEchoService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type UnannotatedEchoServiceClient interface { - Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) - EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) - EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) -} - -type unannotatedEchoServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewUnannotatedEchoServiceClient(cc grpc.ClientConnInterface) UnannotatedEchoServiceClient { - return &unannotatedEchoServiceClient{cc} -} - -func (c *unannotatedEchoServiceClient) Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *unannotatedEchoServiceClient) EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *unannotatedEchoServiceClient) EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { - out := new(UnannotatedSimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// UnannotatedEchoServiceServer is the server API for UnannotatedEchoService service. -type UnannotatedEchoServiceServer interface { - Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) - EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) - EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) -} - -// UnimplementedUnannotatedEchoServiceServer can be embedded to have forward compatible implementations. -type UnimplementedUnannotatedEchoServiceServer struct { -} - -func (*UnimplementedUnannotatedEchoServiceServer) Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") -} -func (*UnimplementedUnannotatedEchoServiceServer) EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") -} -func (*UnimplementedUnannotatedEchoServiceServer) EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") -} - -func RegisterUnannotatedEchoServiceServer(s *grpc.Server, srv UnannotatedEchoServiceServer) { - s.RegisterService(&_UnannotatedEchoService_serviceDesc, srv) -} - -func _UnannotatedEchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).Echo(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).Echo(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _UnannotatedEchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _UnannotatedEchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UnannotatedSimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, req.(*UnannotatedSimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -var _UnannotatedEchoService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService", - HandlerType: (*UnannotatedEchoServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Echo", - Handler: _UnannotatedEchoService_Echo_Handler, - }, - { - MethodName: "EchoBody", - Handler: _UnannotatedEchoService_EchoBody_Handler, - }, - { - MethodName: "EchoDelete", - Handler: _UnannotatedEchoService_EchoDelete_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "examples/internal/proto/examplepb/unannotated_echo_service.proto", -} diff --git a/gateway/internal/casing/BUILD.bazel b/gateway/internal/casing/BUILD.bazel index 94c3fc4..f7ce84c 100644 --- a/gateway/internal/casing/BUILD.bazel +++ b/gateway/internal/casing/BUILD.bazel @@ -1,8 +1,14 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( - name = "go_default_library", + name = "casing", srcs = ["camel.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/casing", visibility = ["//:__subpackages__"], ) + +alias( + name = "go_default_library", + actual = ":casing", + visibility = ["//:__subpackages__"], +) diff --git a/gateway/internal/descriptor/BUILD.bazel b/gateway/internal/descriptor/BUILD.bazel index 9a9269c..0bff1b9 100644 --- a/gateway/internal/descriptor/BUILD.bazel +++ b/gateway/internal/descriptor/BUILD.bazel @@ -3,7 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "descriptor", srcs = [ "grpc_api_configuration.go", "openapi_configuration.go", @@ -13,42 +13,51 @@ go_library( ], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor", deps = [ - "//gateway/internal/casing:go_default_library", - "//gateway/internal/descriptor/apiconfig:go_default_library", - "//gateway/internal/descriptor/openapiconfig:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", - "//httpoptions:go_default_library", + "//gateway/internal/casing", + "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator", + "//gateway/internal/descriptor/apiconfig", + "//gateway/internal/descriptor/openapiconfig", + "//httpoptions", + "//gateway/protoc-gen-openapiv2/options", + "@com_github_binchencoder_gateway_proto//data:go_default_library", - "@com_github_ghodss_yaml//:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "@org_golang_google_protobuf//compiler/protogen:go_default_library", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", - "@org_golang_google_protobuf//encoding/protojson:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/descriptorpb:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "@com_github_golang_glog//:glog", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule", + "@go_googleapis//google/api:annotations_go_proto", + "@io_k8s_sigs_yaml//:yaml", + "@org_golang_google_protobuf//compiler/protogen", + "@org_golang_google_protobuf//encoding/protojson", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/descriptorpb", + "@org_golang_google_protobuf//types/pluginpb", ], ) go_test( - name = "go_default_test", + name = "descriptor_test", size = "small", srcs = [ "grpc_api_configuration_test.go", + "openapi_configuration_test.go", "registry_test.go", "services_test.go", "types_test.go", ], - embed = [":go_default_library"], + embed = [":descriptor"], deps = [ - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", - "@org_golang_google_protobuf//compiler/protogen:go_default_library", - "@org_golang_google_protobuf//encoding/prototext:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/descriptorpb:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "//gateway/internal/descriptor/openapiconfig", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule", + "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-openapiv2/options", + "@org_golang_google_protobuf//compiler/protogen", + "@org_golang_google_protobuf//encoding/prototext", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/descriptorpb", + "@org_golang_google_protobuf//types/pluginpb", ], ) + +alias( + name = "go_default_library", + actual = ":descriptor", + visibility = ["//:__subpackages__"], +) diff --git a/gateway/internal/descriptor/apiconfig/BUILD.bazel b/gateway/internal/descriptor/apiconfig/BUILD.bazel index 66a5dc1..98baaed 100644 --- a/gateway/internal/descriptor/apiconfig/BUILD.bazel +++ b/gateway/internal/descriptor/apiconfig/BUILD.bazel @@ -19,11 +19,17 @@ go_proto_library( compilers = ["//:go_apiv2"], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig", proto = ":apiconfig_proto", - deps = ["//httpoptions:options_go_proto"], + deps = ["//httpoptions"], ) go_library( - name = "go_default_library", + name = "apiconfig", embed = [":apiconfig_go_proto"], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig", ) + +alias( + name = "go_default_library", + actual = ":apiconfig", + visibility = ["//:__subpackages__"], +) diff --git a/gateway/internal/descriptor/grpc_api_configuration.go b/gateway/internal/descriptor/grpc_api_configuration.go index 3cbe319..e125b4c 100644 --- a/gateway/internal/descriptor/grpc_api_configuration.go +++ b/gateway/internal/descriptor/grpc_api_configuration.go @@ -5,10 +5,10 @@ import ( "io/ioutil" "strings" - "github.com/ghodss/yaml" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/apiconfig" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/apiconfig" "google.golang.org/protobuf/encoding/protojson" + "sigs.k8s.io/yaml" ) func loadGrpcAPIServiceFromYAML(yamlFileContents []byte, yamlSourceLogName string) (*apiconfig.GrpcAPIService, error) { diff --git a/gateway/internal/descriptor/openapi_configuration.go b/gateway/internal/descriptor/openapi_configuration.go index 5010128..d8d131d 100644 --- a/gateway/internal/descriptor/openapi_configuration.go +++ b/gateway/internal/descriptor/openapi_configuration.go @@ -4,10 +4,10 @@ import ( "fmt" "io/ioutil" - "github.com/ghodss/yaml" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" "google.golang.org/protobuf/encoding/protojson" + "sigs.k8s.io/yaml" ) func loadOpenAPIConfigFromYAML(yamlFileContents []byte, yamlSourceLogName string) (*openapiconfig.OpenAPIConfig, error) { diff --git a/gateway/internal/descriptor/openapiconfig/BUILD.bazel b/gateway/internal/descriptor/openapiconfig/BUILD.bazel index de3dbf7..c65a584 100644 --- a/gateway/internal/descriptor/openapiconfig/BUILD.bazel +++ b/gateway/internal/descriptor/openapiconfig/BUILD.bazel @@ -15,12 +15,18 @@ go_proto_library( importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig", proto = ":openapiconfig_proto", visibility = ["//:__subpackages__"], - deps = ["//gateway/protoc-gen-openapiv2/options:go_default_library"], + deps = ["//gateway/protoc-gen-openapiv2/options"], ) go_library( - name = "go_default_library", + name = "openapiconfig", embed = [":openapiconfig_go_proto"], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig", visibility = ["//:__subpackages__"], ) + +alias( + name = "go_default_library", + actual = ":openapiconfig", + visibility = ["//:__subpackages__"], +) diff --git a/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go b/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go old mode 100644 new mode 100755 index 25e9f65..e792bd0 --- a/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go +++ b/gateway/internal/descriptor/openapiconfig/openapiconfig.pb.go @@ -1,14 +1,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: gateway/internal/descriptor/openapiconfig/openapiconfig.proto package openapiconfig import ( options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -22,11 +21,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -// OpenAPIFileOption represents OpenAPI options on a file type OpenAPIFileOption struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -82,7 +76,6 @@ func (x *OpenAPIFileOption) GetOption() *options.Swagger { return nil } -// OpenAPIMethodOption represents OpenAPI options on a method type OpenAPIMethodOption struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -138,7 +131,6 @@ func (x *OpenAPIMethodOption) GetOption() *options.Operation { return nil } -// OpenAPIMessageOption represents OpenAPI options on a message type OpenAPIMessageOption struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -194,13 +186,12 @@ func (x *OpenAPIMessageOption) GetOption() *options.Schema { return nil } -// OpenAPIServiceOption represents OpenAPI options on a service type OpenAPIServiceOption struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` // ex: Service + Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` Option *options.Tag `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"` } @@ -250,7 +241,6 @@ func (x *OpenAPIServiceOption) GetOption() *options.Tag { return nil } -// OpenAPIFieldOption represents OpenAPI options on a field type OpenAPIFieldOption struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -306,7 +296,6 @@ func (x *OpenAPIFieldOption) GetOption() *options.JSONSchema { return nil } -// OpenAPIOptions represents OpenAPI protobuf options type OpenAPIOptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -386,7 +375,6 @@ func (x *OpenAPIOptions) GetField() []*OpenAPIFieldOption { return nil } -// OpenAPIConfig represents a set of OpenAPI options type OpenAPIConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/gateway/internal/descriptor/registry.go b/gateway/internal/descriptor/registry.go index 0978e17..d4ff801 100644 --- a/gateway/internal/descriptor/registry.go +++ b/gateway/internal/descriptor/registry.go @@ -5,6 +5,8 @@ import ( "strings" "github.com/golang/glog" + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" @@ -60,14 +62,21 @@ type Registry struct { // useJSONNamesForFields if true json tag name is used for generating fields in OpenAPI definitions, // otherwise the original proto name is used. It's helpful for synchronizing the OpenAPI definition - // with grpc-gateway response, if it uses json tags for marshaling. + // with gRPC-Gateway response, if it uses json tags for marshaling. useJSONNamesForFields bool - // useFQNForOpenAPIName if true OpenAPI names will use the full qualified name (FQN) from proto definition, - // and generate a dot-separated OpenAPI name concatenating all elements from the proto FQN. - // If false, the default behavior is to concat the last 2 elements of the FQN if they are unique, otherwise concat - // all the elements of the FQN without any separator - useFQNForOpenAPIName bool + // openAPINamingStrategy is the naming strategy to use for assigning OpenAPI field and parameter names. This can be one of the following: + // - `legacy`: use the legacy naming strategy from protoc-gen-swagger, that generates unique but not necessarily + // maximally concise names. Components are concatenated directly, e.g., `MyOuterMessageMyNestedMessage`. + // - `simple`: use a simple heuristic for generating unique and concise names. Components are concatenated using + // dots as a separator, e.g., `MyOuterMesage.MyNestedMessage` (if `MyNestedMessage` alone is unique, + // `MyNestedMessage` will be used as the OpenAPI name). + // - `fqn`: always use the fully-qualified name of the proto message (leading dot removed) as the OpenAPI + // name. + openAPINamingStrategy string + + // visibilityRestrictionSelectors is a map of selectors for `google.api.VisibilityRule`s that will be included in the OpenAPI output. + visibilityRestrictionSelectors map[string]bool // useGoTemplate determines whether you want to use GO templates // in your protofile comments @@ -76,6 +85,9 @@ type Registry struct { // enumsAsInts render enum as integer, as opposed to string enumsAsInts bool + // omitEnumDefaultValue omits default value of enum + omitEnumDefaultValue bool + // disableDefaultErrors disables the generation of the default error types. // This is useful for users who have defined custom error handling. disableDefaultErrors bool @@ -89,6 +101,9 @@ type Registry struct { // has no HttpRule annotation. warnOnUnboundMethods bool + // proto3OptionalNullable specifies whether Proto3 Optional fields should be marked as x-nullable. + proto3OptionalNullable bool + // fileOptions is a mapping of file name to additional OpenAPI file options fileOptions map[string]*options.Swagger @@ -111,6 +126,12 @@ type Registry struct { // omitPackageDoc, if false, causes a package comment to be included in the generated code. omitPackageDoc bool + + // recursiveDepth sets the maximum depth of a field parameter + recursiveDepth int + + // annotationMap is used to check for duplicate HTTP annotations + annotationMap map[annotationIdentifier]struct{} } type repeatedFieldSeparator struct { @@ -118,6 +139,12 @@ type repeatedFieldSeparator struct { sep rune } +type annotationIdentifier struct { + method string + pathTemplate string + service *Service +} + var ( // Reg is the global dictionary. Reg *Registry @@ -126,12 +153,14 @@ var ( // NewRegistry returns a new Registry. func NewRegistry() *Registry { return &Registry{ - msgs: make(map[string]*Message), - enums: make(map[string]*Enum), - files: make(map[string]*File), - pkgMap: make(map[string]string), - pkgAliases: make(map[string]string), - externalHTTPRules: make(map[string][]*annotations.HttpRule), + msgs: make(map[string]*Message), + enums: make(map[string]*Enum), + files: make(map[string]*File), + pkgMap: make(map[string]string), + pkgAliases: make(map[string]string), + externalHTTPRules: make(map[string][]*annotations.HttpRule), + openAPINamingStrategy: "legacy", + visibilityRestrictionSelectors: make(map[string]bool), repeatedPathParamSeparator: repeatedFieldSeparator{ name: "csv", sep: ',', @@ -141,6 +170,8 @@ func NewRegistry() *Registry { messageOptions: make(map[string]*options.Schema), serviceOptions: make(map[string]*options.Tag), fieldOptions: make(map[string]*options.JSONSchema), + annotationMap: make(map[annotationIdentifier]struct{}), + recursiveDepth: 1000, } } @@ -150,6 +181,10 @@ func (r *Registry) Load(req *pluginpb.CodeGeneratorRequest) error { if err != nil { return err } + // Note: keep in mind that this might be not enough because + // protogen.Plugin is used only to load files here. + // The support for features must be set on the pluginpb.CodeGeneratorResponse. + codegenerator.SetSupportedFeaturesOnPluginGen(gen) return r.load(gen) } @@ -367,6 +402,16 @@ func (r *Registry) SetStandalone(standalone bool) { r.standalone = standalone } +// SetRecursiveDepth records the max recursion count +func (r *Registry) SetRecursiveDepth(count int) { + r.recursiveDepth = count +} + +// GetRecursiveDepth returns the max recursion count +func (r *Registry) GetRecursiveDepth() int { + return r.recursiveDepth +} + // ReserveGoPackageAlias reserves the unique alias of go package. // If succeeded, the alias will be never used for other packages in generated go files. // If failed, the alias is already taken by another package, so you need to use another @@ -491,13 +536,15 @@ func (r *Registry) GetUseJSONNamesForFields() bool { } // SetUseFQNForOpenAPIName sets useFQNForOpenAPIName +// Deprecated: use SetOpenAPINamingStrategy instead. func (r *Registry) SetUseFQNForOpenAPIName(use bool) { - r.useFQNForOpenAPIName = use + r.openAPINamingStrategy = "fqn" } // GetUseFQNForOpenAPIName returns useFQNForOpenAPIName +// Deprecated: Use GetOpenAPINamingStrategy(). func (r *Registry) GetUseFQNForOpenAPIName() bool { - return r.useFQNForOpenAPIName + return r.openAPINamingStrategy == "fqn" } // GetMergeFileName return the target merge OpenAPI file name @@ -505,6 +552,16 @@ func (r *Registry) GetMergeFileName() string { return r.mergeFileName } +// SetOpenAPINamingStrategy sets the naming strategy to be used. +func (r *Registry) SetOpenAPINamingStrategy(strategy string) { + r.openAPINamingStrategy = strategy +} + +// GetOpenAPINamingStrategy retrieves the naming strategy that is in use. +func (r *Registry) GetOpenAPINamingStrategy() string { + return r.openAPINamingStrategy +} + // SetUseGoTemplate sets useGoTemplate func (r *Registry) SetUseGoTemplate(use bool) { r.useGoTemplate = use @@ -525,6 +582,29 @@ func (r *Registry) GetEnumsAsInts() bool { return r.enumsAsInts } +// SetOmitEnumDefaultValue sets omitEnumDefaultValue +func (r *Registry) SetOmitEnumDefaultValue(omit bool) { + r.omitEnumDefaultValue = omit +} + +// GetOmitEnumDefaultValue returns omitEnumDefaultValue +func (r *Registry) GetOmitEnumDefaultValue() bool { + return r.omitEnumDefaultValue +} + +// SetVisibilityRestrictionSelectors sets the visibility restriction selectors. +func (r *Registry) SetVisibilityRestrictionSelectors(selectors []string) { + r.visibilityRestrictionSelectors = make(map[string]bool) + for _, selector := range selectors { + r.visibilityRestrictionSelectors[strings.TrimSpace(selector)] = true + } +} + +// GetVisibilityRestrictionSelectors retrieves he visibility restriction selectors. +func (r *Registry) GetVisibilityRestrictionSelectors() map[string]bool { + return r.visibilityRestrictionSelectors +} + // SetDisableDefaultErrors sets disableDefaultErrors func (r *Registry) SetDisableDefaultErrors(use bool) { r.disableDefaultErrors = use @@ -565,6 +645,16 @@ func (r *Registry) GetOmitPackageDoc() bool { return r.omitPackageDoc } +// SetProto3OptionalNullable set proto3OtionalNullable +func (r *Registry) SetProto3OptionalNullable(proto3OtionalNullable bool) { + r.proto3OptionalNullable = proto3OtionalNullable +} + +// GetProto3OptionalNullable returns proto3OtionalNullable +func (r *Registry) GetProto3OptionalNullable() bool { + return r.proto3OptionalNullable +} + // RegisterOpenAPIOptions registers OpenAPI options func (r *Registry) RegisterOpenAPIOptions(opts *openapiconfig.OpenAPIOptions) error { if opts == nil { @@ -660,3 +750,20 @@ func (r *Registry) GetOpenAPIFieldOption(qualifiedField string) (*options.JSONSc opt, ok := r.fieldOptions[qualifiedField] return opt, ok } + +func (r *Registry) FieldName(f *Field) string { + if r.useJSONNamesForFields { + return f.GetJsonName() + } + return f.GetName() +} + +func (r *Registry) CheckDuplicateAnnotation(httpMethod string, httpTemplate string, svc *Service) error { + a := annotationIdentifier{method: httpMethod, pathTemplate: httpTemplate, service: svc} + _, ok := r.annotationMap[a] + if ok { + return fmt.Errorf("duplicate annotation: method=%s, template=%s", httpMethod, httpTemplate) + } + r.annotationMap[a] = struct{}{} + return nil +} diff --git a/gateway/internal/descriptor/registry_test.go b/gateway/internal/descriptor/registry_test.go index 39cdb92..a886063 100644 --- a/gateway/internal/descriptor/registry_test.go +++ b/gateway/internal/descriptor/registry_test.go @@ -25,6 +25,7 @@ func newGeneratorFromSources(req *pluginpb.CodeGeneratorRequest, sources ...stri } func loadFileWithCodeGeneratorRequest(t *testing.T, reg *Registry, req *pluginpb.CodeGeneratorRequest, sources ...string) []*descriptorpb.FileDescriptorProto { + t.Helper() plugin, err := newGeneratorFromSources(req, sources...) if err != nil { t.Fatalf("failed to create a generator: %v", err) @@ -37,6 +38,7 @@ func loadFileWithCodeGeneratorRequest(t *testing.T, reg *Registry, req *pluginpb } func loadFile(t *testing.T, reg *Registry, src string) *descriptorpb.FileDescriptorProto { + t.Helper() fds := loadFileWithCodeGeneratorRequest(t, reg, &pluginpb.CodeGeneratorRequest{}, src) return fds[0] } @@ -46,6 +48,7 @@ func TestLoadFile(t *testing.T) { fd := loadFile(t, reg, ` name: 'example.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > message_type < name: 'ExampleMessage' field < @@ -62,7 +65,7 @@ func TestLoadFile(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") return } - wantPkg := GoPackage{Path: ".", Name: "example"} + wantPkg := GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example", Name: "example"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -102,6 +105,7 @@ func TestLoadFileNestedPackage(t *testing.T) { loadFile(t, reg, ` name: 'example.proto' package: 'example.nested.nested2' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.nested.nested2' > `) file := reg.files["example.proto"] @@ -109,7 +113,7 @@ func TestLoadFileNestedPackage(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") return } - wantPkg := GoPackage{Path: ".", Name: "example_nested_nested2"} + wantPkg := GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.nested.nested2", Name: "example_nested_nested2"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -120,6 +124,7 @@ func TestLoadFileWithDir(t *testing.T) { loadFile(t, reg, ` name: 'path/to/example.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `) file := reg.files["path/to/example.proto"] @@ -127,7 +132,7 @@ func TestLoadFileWithDir(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") return } - wantPkg := GoPackage{Path: "path/to", Name: "example"} + wantPkg := GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example", Name: "example"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -137,6 +142,7 @@ func TestLoadFileWithoutPackage(t *testing.T) { reg := NewRegistry() loadFile(t, reg, ` name: 'path/to/example_file.proto' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example_file' > `) file := reg.files["path/to/example_file.proto"] @@ -144,7 +150,7 @@ func TestLoadFileWithoutPackage(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto") return } - wantPkg := GoPackage{Path: "path/to", Name: "example_file"} + wantPkg := GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example_file", Name: "example_file"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -157,6 +163,7 @@ func TestLoadFileWithMapping(t *testing.T) { }, ` name: 'path/to/example.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `) file := reg.files["path/to/example.proto"] @@ -175,10 +182,12 @@ func TestLoadFileWithPackageNameCollision(t *testing.T) { loadFile(t, reg, ` name: 'path/to/another.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `) loadFile(t, reg, ` name: 'path/to/example.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `) if err := reg.ReserveGoPackageAlias("ioutil", "io/ioutil"); err != nil { t.Fatalf("reg.ReserveGoPackageAlias(%q) failed with %v; want success", "ioutil", err) @@ -186,6 +195,7 @@ func TestLoadFileWithPackageNameCollision(t *testing.T) { loadFile(t, reg, ` name: 'path/to/ioutil.proto' package: 'ioutil' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/ioutil' > `) file := reg.files["path/to/another.proto"] @@ -193,7 +203,7 @@ func TestLoadFileWithPackageNameCollision(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/another.proto") return } - wantPkg := GoPackage{Path: "path/to", Name: "example"} + wantPkg := GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example", Name: "example"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -203,7 +213,7 @@ func TestLoadFileWithPackageNameCollision(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/example.proto") return } - wantPkg = GoPackage{Path: "path/to", Name: "example", Alias: ""} + wantPkg = GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example", Name: "example", Alias: ""} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -213,7 +223,7 @@ func TestLoadFileWithPackageNameCollision(t *testing.T) { t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/ioutil.proto") return } - wantPkg = GoPackage{Path: "path/to", Name: "ioutil", Alias: "ioutil_0"} + wantPkg = GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway/runtime/internal/ioutil", Name: "ioutil", Alias: "ioutil_0"} if got, want := file.GoPkg, wantPkg; got != want { t.Errorf("file.GoPkg = %#v; want %#v", got, want) } @@ -226,9 +236,11 @@ func TestLoadFileWithIdenticalGoPkg(t *testing.T) { }, ` name: 'path/to/another.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `, ` name: 'path/to/example.proto' package: 'example' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > `) file := reg.files["path/to/example.proto"] @@ -259,6 +271,7 @@ func TestLookupMsgWithoutPackage(t *testing.T) { reg := NewRegistry() fd := loadFile(t, reg, ` name: 'example.proto' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > message_type < name: 'ExampleMessage' field < @@ -285,6 +298,7 @@ func TestLookupMsgWithNestedPackage(t *testing.T) { fd := loadFile(t, reg, ` name: 'example.proto' package: 'nested.nested2.mypackage' + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > message_type < name: 'ExampleMessage' field < @@ -359,84 +373,6 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { req string consistent bool }{ - // root package, no explicit go package - { - req: ` - file_to_generate: 'a.proto' - file_to_generate: 'b.proto' - proto_file < - name: 'a.proto' - message_type < name: 'A' > - service < - name: "AService" - method < - name: "Meth" - input_type: "A" - output_type: "A" - options < - [google.api.http] < post: "/v1/a" body: "*" > - > - > - > - > - proto_file < - name: 'b.proto' - message_type < name: 'B' > - service < - name: "BService" - method < - name: "Meth" - input_type: "B" - output_type: "B" - options < - [google.api.http] < post: "/v1/b" body: "*" > - > - > - > - > - `, - consistent: false, - }, - // named package, no explicit go package - { - req: ` - file_to_generate: 'a.proto' - file_to_generate: 'b.proto' - proto_file < - name: 'a.proto' - package: 'example.foo' - message_type < name: 'A' > - service < - name: "AService" - method < - name: "Meth" - input_type: "A" - output_type: "A" - options < - [google.api.http] < post: "/v1/a" body: "*" > - > - > - > - > - proto_file < - name: 'b.proto' - package: 'example.foo' - message_type < name: 'B' > - service < - name: "BService" - method < - name: "Meth" - input_type: "B" - output_type: "B" - options < - [google.api.http] < post: "/v1/b" body: "*" > - > - > - > - > - `, - consistent: true, - }, // root package, explicit go package { req: ` @@ -444,7 +380,7 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { file_to_generate: 'b.proto' proto_file < name: 'a.proto' - options < go_package: 'foo' > + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.foo' > message_type < name: 'A' > service < name: "AService" @@ -460,7 +396,7 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { > proto_file < name: 'b.proto' - options < go_package: 'foo' > + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.foo' > message_type < name: 'B' > service < name: "BService" @@ -485,7 +421,7 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { proto_file < name: 'a.proto' package: 'example.foo' - options < go_package: 'foo' > + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.foo' > message_type < name: 'A' > service < name: "AService" @@ -502,7 +438,7 @@ func TestLoadWithInconsistentTargetPackage(t *testing.T) { proto_file < name: 'b.proto' package: 'example.foo' - options < go_package: 'foo' > + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example.foo' > message_type < name: 'B' > service < name: "BService" @@ -580,6 +516,7 @@ func TestUnboundExternalHTTPRules(t *testing.T) { loadFile(t, reg, ` name: "path/to/example.proto", package: "example" + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > message_type < name: "StringMessage" field < @@ -606,7 +543,7 @@ func TestRegisterOpenAPIOptions(t *testing.T) { proto_file < name: 'a.proto' package: 'example.foo' - options < go_package: 'foo' > + options < go_package: 'github.com/grpc-ecosystem/grpc-gateway/runtime/internal/example' > message_type < name: 'ExampleMessage' field < diff --git a/gateway/internal/descriptor/services.go b/gateway/internal/descriptor/services.go index 8e5187c..6e2249e 100644 --- a/gateway/internal/descriptor/services.go +++ b/gateway/internal/descriptor/services.go @@ -328,7 +328,7 @@ func (r *Registry) newParam(meth *Method, path string) (Parameter, error) { if IsWellKnownType(*target.TypeName) { glog.V(2).Infoln("found well known aggregate type:", target) } else { - return Parameter{}, fmt.Errorf("aggregate type %s in parameter of %s.%s: %s", target.Type, meth.Service.GetName(), meth.GetName(), path) + return Parameter{}, fmt.Errorf("%s.%s: %s is a protobuf message type. Protobuf message types cannot be used as path parameters, use a scalar value type (such as string) instead", meth.Service.GetName(), meth.GetName(), path) } } return Parameter{ @@ -408,6 +408,9 @@ func (r *Registry) resolveFieldPath(msg *Message, path string, isPathParam bool) if !(isPathParam || r.allowRepeatedFieldsInBody) && f.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REPEATED { return nil, fmt.Errorf("repeated field not allowed in field path: %s in %s", f.GetName(), path) } + if isPathParam && f.GetProto3Optional() { + return nil, fmt.Errorf("optional field not allowed in field path: %s in %s", f.GetName(), path) + } result = append(result, FieldPathComponent{Name: c, Target: f}) } return result, nil diff --git a/gateway/internal/descriptor/services_test.go b/gateway/internal/descriptor/services_test.go index 6214fcc..8ce91f1 100644 --- a/gateway/internal/descriptor/services_test.go +++ b/gateway/internal/descriptor/services_test.go @@ -2,6 +2,7 @@ package descriptor import ( "reflect" + "strings" "testing" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" @@ -1347,3 +1348,100 @@ func TestExtractServicesWithDeleteBody(t *testing.T) { t.Log(err) } } + +func TestCauseErrorWithPathParam(t *testing.T) { + src := ` + name: "path/to/example.proto", + package: "example" + message_type < + name: "TypeMessage" + field < + name: "message" + type: TYPE_MESSAGE + type_name: 'ExampleMessage' + number: 1, + label: LABEL_OPTIONAL + > + > + service < + name: "ExampleService" + method < + name: "Echo" + input_type: "TypeMessage" + output_type: "TypeMessage" + options < + [google.api.http] < + get: "/v1/example/echo/{message=*}" + > + > + > + > + ` + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { + t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) + } + target := "path/to/example.proto" + reg := NewRegistry() + input := []*descriptorpb.FileDescriptorProto{&fd} + reg.loadFile(fd.GetName(), &protogen.File{ + Proto: &fd, + }) + // switch this field to see the error + wantErr := true + err := reg.loadServices(reg.files[target]) + if got, want := err != nil, wantErr; got != want { + if want { + t.Errorf("loadServices(%q, %q) succeeded; want an error", target, input) + } + t.Errorf("loadServices(%q, %q) failed with %v; want success", target, input, err) + } +} + +func TestOptionalProto3URLPathMappingError(t *testing.T) { + src := ` + name: "path/to/example.proto" + package: "example" + message_type < + name: "StringMessage" + field < + name: "field1" + number: 1 + type: TYPE_STRING + proto3_optional: true + > + > + service < + name: "ExampleService" + method < + name: "Echo" + input_type: "StringMessage" + output_type: "StringMessage" + options < + [google.api.http] < + get: "/v1/example/echo/{field1=*}" + > + > + > + > + ` + var fd descriptorpb.FileDescriptorProto + if err := prototext.Unmarshal([]byte(src), &fd); err != nil { + t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err) + } + target := "path/to/example.proto" + reg := NewRegistry() + input := []*descriptorpb.FileDescriptorProto{&fd} + reg.loadFile(fd.GetName(), &protogen.File{ + Proto: &fd, + }) + wantErrMsg := "field not allowed in field path: field1 in field1" + err := reg.loadServices(reg.files[target]) + if err != nil { + if !strings.Contains(err.Error(), wantErrMsg) { + t.Errorf("loadServices(%q, %q) failed with %v; want %s", target, input, err, wantErrMsg) + } + } else { + t.Errorf("loadServices(%q, %q) expcted an error %s, got nil", target, input, wantErrMsg) + } +} diff --git a/gateway/internal/descriptor/types.go b/gateway/internal/descriptor/types.go index ef2c0d7..f8b8626 100644 --- a/gateway/internal/descriptor/types.go +++ b/gateway/internal/descriptor/types.go @@ -27,7 +27,7 @@ type GoPackage struct { Path string // Name is the package name of the package Name string - // Alias is an alias of the package unique within the current invocation of grpc-gateway generator. + // Alias is an alias of the package unique within the current invocation of gRPC-Gateway generator. Alias string } @@ -509,6 +509,8 @@ func (p Parameter) ConvertFuncExpr() (string, error) { tbl := proto3ConvertFuncs if !p.IsProto2() && p.IsRepeated() { tbl = proto3RepeatedConvertFuncs + } else if !p.IsProto2() && p.IsOptionalProto3() { + tbl = proto3OptionalConvertFuncs } else if p.IsProto2() && !p.IsRepeated() { tbl = proto2ConvertFuncs } else if p.IsProto2() && p.IsRepeated() { @@ -574,6 +576,14 @@ func (p FieldPath) IsNestedProto3() bool { return false } +// IsOptionalProto3 indicates whether the FieldPath is a proto3 optional field. +func (p FieldPath) IsOptionalProto3() bool { + if len(p) == 0 { + return false + } + return p[0].Target.GetProto3Optional() +} + // AssignableExpr is an assignable expression in Go to be used to assign a value to the target field. // It starts with "msgExpr", which is the go expression of the method request object. func (p FieldPath) AssignableExpr(msgExpr string) string { @@ -585,8 +595,10 @@ func (p FieldPath) AssignableExpr(msgExpr string) string { var preparations []string components := msgExpr for i, c := range p { - // Check if it is a oneOf field. - if c.Target.OneofIndex != nil { + // We need to check if the target is not proto3_optional first. + // Under the hood, proto3_optional uses oneof to signal to old proto3 clients + // that presence is tracked for this field. This oneof is known as a "synthetic" oneof. + if !c.Target.GetProto3Optional() && c.Target.OneofIndex != nil { index := c.Target.OneofIndex msg := c.Target.Message oneOfName := casing.Camel(msg.GetOneofDecl()[*index].GetName()) @@ -662,6 +674,18 @@ var ( descriptorpb.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64", } + proto3OptionalConvertFuncs = func() map[descriptorpb.FieldDescriptorProto_Type]string { + result := make(map[descriptorpb.FieldDescriptorProto_Type]string) + for typ, converter := range proto3ConvertFuncs { + // TODO: this will use convert functions from proto2. + // The converters returning pointers should be moved + // to a more generic file. + result[typ] = converter + "P" + } + return result + }() + + // TODO: replace it with a IIFE proto3RepeatedConvertFuncs = map[descriptorpb.FieldDescriptorProto_Type]string{ descriptorpb.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64Slice", descriptorpb.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32Slice", diff --git a/gateway/internal/descriptor/types_test.go b/gateway/internal/descriptor/types_test.go index 60e5bc0..1887764 100644 --- a/gateway/internal/descriptor/types_test.go +++ b/gateway/internal/descriptor/types_test.go @@ -3,8 +3,8 @@ package descriptor import ( "testing" - descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor" "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/types/descriptorpb" ) func TestGoPackageStandard(t *testing.T) { @@ -130,7 +130,7 @@ func TestFieldPath(t *testing.T) { } fds = append(fds, &fd) } - nest := &Message{ + nest1 := &Message{ DescriptorProto: fds[0].MessageType[0], Fields: []*Field{ {FieldDescriptorProto: fds[0].MessageType[0].Field[0]}, @@ -147,7 +147,7 @@ func TestFieldPath(t *testing.T) { file1 := &File{ FileDescriptorProto: fds[0], GoPkg: GoPackage{Path: "example", Name: "example"}, - Messages: []*Message{nest}, + Messages: []*Message{nest1}, } file2 := &File{ FileDescriptorProto: fds[1], @@ -170,7 +170,7 @@ func TestFieldPath(t *testing.T) { c2 := FieldPathComponent{ Name: "nest2_field", - Target: nest.Fields[0], + Target: nest1.Fields[0], } if got, want := c2.ValueExpr(), "Nest2Field"; got != want { t.Errorf("c2.ValueExpr() = %q; want %q", got, want) @@ -182,7 +182,7 @@ func TestFieldPath(t *testing.T) { fp := FieldPath{ c1, c2, c1, FieldPathComponent{ Name: "terminal_field", - Target: nest.Fields[1], + Target: nest1.Fields[1], }, } if got, want := fp.AssignableExpr("resp"), "resp.GetNestField().Nest2Field.GetNestField().TerminalField"; got != want { diff --git a/gateway/internal/generator/BUILD.bazel b/gateway/internal/generator/BUILD.bazel index c17f265..fec2a2c 100644 --- a/gateway/internal/generator/BUILD.bazel +++ b/gateway/internal/generator/BUILD.bazel @@ -3,11 +3,14 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "generator", srcs = ["generator.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/internal/generator", - deps = [ - "//gateway/internal/descriptor:go_default_library", - "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", - ], + deps = ["//gateway/internal/descriptor:go_default_library"], +) + +alias( + name = "go_default_library", + actual = ":generator", + visibility = ["//:__subpackages__"], ) diff --git a/gateway/protoc-gen-grpc-gateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/BUILD.bazel index edbd060..6d60b23 100644 --- a/gateway/protoc-gen-grpc-gateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/BUILD.bazel @@ -4,20 +4,21 @@ load("@io_bazel_rules_go//proto:compiler.bzl", "go_proto_compiler") package(default_visibility = ["//visibility:private"]) go_library( - name = "go_default_library", + name = "protoc-gen-grpc-gateway_lib", srcs = ["main.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway", deps = [ + "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator", "//gateway/internal/descriptor:go_default_library", - "//gateway/protoc-gen-grpc-gateway/internal/gengateway:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@org_golang_google_protobuf//compiler/protogen:go_default_library", + "//gateway/protoc-gen-grpc-gateway/internal/gengateway", + "@com_github_golang_glog//:glog", + "@org_golang_google_protobuf//compiler/protogen", ], ) go_binary( name = "protoc-gen-grpc-gateway", - embed = [":go_default_library"], + embed = [":protoc-gen-grpc-gateway_lib"], visibility = ["//visibility:public"], ) @@ -34,7 +35,7 @@ go_proto_compiler( "//gateway/runtime:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes:go_default_library", "@org_golang_google_grpc//grpclog:go_default_library", @@ -45,8 +46,8 @@ go_proto_compiler( ) go_test( - name = "go_default_test", + name = "protoc-gen-grpc-gateway_test", srcs = ["main_test.go"], - embed = [":go_default_library"], - deps = ["//gateway/internal/descriptor:go_default_library"], + embed = [":protoc-gen-grpc-gateway_lib"], + deps = ["//gateway/internal/descriptor"], ) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel index 2e868bb..555e8fa 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/BUILD.bazel @@ -3,7 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "gengateway", srcs = [ "doc.go", "generator.go", @@ -11,29 +11,35 @@ go_library( ], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-grpc-gateway/internal/gengateway", deps = [ - "//httpoptions:go_default_library", - "//gateway/internal/casing:go_default_library", - "//gateway/internal/descriptor:go_default_library", - "//gateway/internal/generator:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "//httpoptions", + "//gateway/internal/casing", + "//gateway/internal/descriptor", + "//gateway/internal/generator", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", + "@com_github_golang_glog//:glog", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/pluginpb", ], ) go_test( - name = "go_default_test", + name = "gengateway_test", size = "small", srcs = [ "generator_test.go", "template_test.go", ], - embed = [":go_default_library"], + embed = [":gengateway"], deps = [ - "//gateway/internal/descriptor:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/descriptorpb:go_default_library", + "//gateway/internal/descriptor", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/descriptorpb", ], ) + +alias( + name = "go_default_library", + actual = ":gengateway", + visibility = ["//protoc-gen-grpc-gateway:__subpackages__"], +) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go index 9e9e682..42f26d3 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go @@ -3,15 +3,16 @@ package gengateway import ( "errors" "fmt" + "go/format" + "path" + "github.com/golang/glog" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" // gen "github.com/grpc-ecosystem/grpc-gateway/v2/internal/generator" gen "github.com/binchencoder/ease-gateway/gateway/internal/generator" - "go/format" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/pluginpb" - "path" ) var ( @@ -41,7 +42,7 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix st "unicode/utf8": "", // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime", "github.com/binchencoder/ease-gateway/gateway/runtime": "", - "github.com/grpc-ecosystem/grpc-gateway/v2/utilities": "", + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities": "", "google.golang.org/protobuf/proto": "", "github.com/binchencoder/gateway-proto/data": "vexpb", "github.com/binchencoder/gateway-proto/frontend": "fpb", @@ -52,10 +53,10 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix st "github.com/binchencoder/skylb-api/proto": "skypb", "google.golang.org/grpc": "", "google.golang.org/grpc/codes": "", - "google.golang.org/grpc/naming": "", - "google.golang.org/grpc/grpclog": "", - "google.golang.org/grpc/metadata": "", - "google.golang.org/grpc/status": "", + // "google.golang.org/grpc/naming": "", + "google.golang.org/grpc/grpclog": "", + "google.golang.org/grpc/metadata": "", + "google.golang.org/grpc/status": "", } { pkg := descriptor.GoPackage{ Path: pkgpath, diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go index 9e30d4c..e2d73f3 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator_test.go @@ -78,6 +78,7 @@ func newExampleFileDescriptorWithGoPkg(gp *descriptor.GoPackage, filenamePrefix func TestGenerator_Generate(t *testing.T) { g := new(generator) + g.reg = descriptor.NewRegistry() result, err := g.Generate([]*descriptor.File{ crossLinkFixture(newExampleFileDescriptorWithGoPkg(&descriptor.GoPackage{ Path: "example.com/path/to/example", diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go index 5cd7480..5b039c0 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go @@ -39,7 +39,7 @@ func (b binding) GetBodyFieldPath() string { return "*" } -// GetBodyFieldPath returns the binding body's struct field name. +// GetBodyFieldStructName returns the binding body's struct field name. func (b binding) GetBodyFieldStructName() (string, error) { if b.Body != nil && len(b.Body.FieldPath) != 0 { return casing.Camel(b.Body.FieldPath.String()), nil @@ -173,11 +173,6 @@ func applyTemplate(p param, reg *descriptor.Registry) (string, error) { if err := headerTemplate.Execute(w, p); err != nil { return "", err } - - if err := validatorTemplate.Execute(w, p); err != nil { - return "", err - } - var targetServices []*descriptor.Service for _, msg := range p.Messages { @@ -195,6 +190,10 @@ func applyTemplate(p param, reg *descriptor.Registry) (string, error) { methName := casing.Camel(*meth.Name) meth.Name = &methName for _, b := range meth.Bindings { + if err := reg.CheckDuplicateAnnotation(b.HTTPMethod, b.PathTmpl.Template, svc); err != nil { + return "", err + } + methodWithBindingsSeen = true if err := handlerTemplate.Execute(w, binding{ Binding: b, @@ -651,15 +650,6 @@ var ( } return nil } - if err := handleSend(); err != nil { - if cerr := stream.CloseSend(); cerr != nil { - grpclog.Infof("Failed to terminate client stream: %v", cerr) - } - if err == io.EOF { - return stream, metadata, nil - } - return nil, metadata, err - } go func() { for { if err := handleSend(); err != nil { @@ -816,12 +806,17 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Server(ctx context.Context, var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") + var err error + {{- if $b.PathTmpl }} + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}", runtime.WithHTTPPathPattern("{{$b.PathTmpl.Template}}")) + {{- else -}} + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") + {{- end }} if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}(ctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -872,7 +867,7 @@ func init() { {{range $svc := .Services}} // Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint is same as Register{{$svc.GetName}}{{$.RegisterFuncSuffix}} but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. -func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint(mux *runtime.ServeMux) (err error) { +func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint(ctx context.Context, mux *runtime.ServeMux) (err error) { // conn, err := grpc.Dial(endpoint, opts...) // if err != nil { // return err @@ -892,8 +887,8 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint(mux *runtime.S // }() // }() - // return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(ctx, mux, conn) - return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(nil, mux, nil) + return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(ctx, mux, conn) + // return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(nil, mux, nil) } // Register{{$svc.GetName}}{{$.RegisterFuncSuffix}} registers the http handlers for service {{$svc.GetName}} to "mux". @@ -939,12 +934,17 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, {{- end }} defer cancel() // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") + var err error + {{- if $b.PathTmpl }} + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}", runtime.WithHTTPPathPattern("{{$b.PathTmpl.Template}}")) + {{- else -}} + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}") + {{- end }} if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go index 28db071..b9730a6 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template_test.go @@ -30,6 +30,14 @@ func crossLinkFixture(f *descriptor.File) *descriptor.File { return f } +func compilePath(t *testing.T, path string) httprule.Template { + parsed, err := httprule.Parse(path) + if err != nil { + t.Fatalf("httprule.Parse(%q) failed with %v; want success", path, err) + } + return parsed.Compile() +} + func TestApplyTemplateHeader(t *testing.T) { msgdesc := &descriptorpb.DescriptorProto{ Name: proto.String("ExampleMessage"), @@ -186,8 +194,9 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { { HTTPMethod: "POST", PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, + Version: 1, + OpCodes: []int{0, 0}, + Template: "/v1", }, PathParams: []descriptor.Parameter{ { @@ -246,7 +255,7 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { if want := `pattern_ExampleService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{0, 0}, []string(nil), ""))`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } - if want := `rctx, err := runtime.AnnotateContext(ctx, mux, req, "/example.ExampleService/Echo")`; !strings.Contains(got, want) { + if want := `ctx, err = runtime.AnnotateContext(ctx, mux, req, "/example.ExampleService/Echo", runtime.WithHTTPPathPattern("/v1"))`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } } @@ -454,7 +463,7 @@ func TestApplyTemplateInProcess(t *testing.T) { serverStreaming: false, sigWant: []string{ `func local_request_ExampleService_Echo_0(ctx context.Context, marshaler runtime.Marshaler, server ExampleServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {`, - `resp, md, err := local_request_ExampleService_Echo_0(rctx, inboundMarshaler, server, req, pathParams)`, + `resp, md, err := local_request_ExampleService_Echo_0(ctx, inboundMarshaler, server, req, pathParams)`, }, }, { @@ -675,7 +684,7 @@ func TestIdentifierCapitalization(t *testing.T) { OutputType: proto.String("example_response"), } meth2 := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Exampl_eGet"), + Name: proto.String("Exampl_ePost"), InputType: proto.String("Exam_pleRequest"), OutputType: proto.String("example_response"), } @@ -728,7 +737,7 @@ func TestIdentifierCapitalization(t *testing.T) { ResponseType: msg2, Bindings: []*descriptor.Binding{ { - HTTPMethod: "GET", + HTTPMethod: "POST", Body: &descriptor.Body{FieldPath: nil}, }, }, @@ -746,7 +755,7 @@ func TestIdentifierCapitalization(t *testing.T) { if want := `msg, err := client.ExampleGe2T(ctx, &protoReq, grpc.Header(&metadata.HeaderMD)`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } - if want := `msg, err := client.ExamplEGet(ctx, &protoReq, grpc.Header(&metadata.HeaderMD)`; !strings.Contains(got, want) { + if want := `msg, err := client.ExamplEPost(ctx, &protoReq, grpc.Header(&metadata.HeaderMD)`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } if want := `var protoReq ExamPleRequest`; !strings.Contains(got, want) { @@ -756,3 +765,164 @@ func TestIdentifierCapitalization(t *testing.T) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } } + +func TestDuplicatePathsInSameService(t *testing.T) { + msgdesc := &descriptorpb.DescriptorProto{ + Name: proto.String("ExampleMessage"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + TypeName: proto.String(".google.protobuf.StringValue"), + Number: proto.Int32(1), + }, + }, + } + meth1 := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("Echo"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + } + meth2 := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("Echo2"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + } + svc := &descriptorpb.ServiceDescriptorProto{ + Name: proto.String("ExampleService"), + Method: []*descriptorpb.MethodDescriptorProto{meth1, meth2}, + } + msg := &descriptor.Message{ + DescriptorProto: msgdesc, + } + binding := &descriptor.Binding{ + Index: 1, + PathTmpl: compilePath(t, "/v1/example/echo"), + HTTPMethod: "GET", + PathParams: nil, + Body: nil, + } + file := descriptor.File{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + Name: proto.String("example.proto"), + Package: proto.String("example"), + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: []*descriptor.Message{msg}, + Services: []*descriptor.Service{ + { + ServiceDescriptorProto: svc, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth1, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{binding}, + }, + { + MethodDescriptorProto: meth2, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{binding}, + }, + }, + }, + }, + } + _, err := applyTemplate(param{File: crossLinkFixture(&file), RegisterFuncSuffix: "Handler", AllowPatchFeature: true}, descriptor.NewRegistry()) + if err == nil { + t.Errorf("applyTemplate(%#v) succeeded; want an error", file) + return + } +} + +func TestDuplicatePathsInDifferentService(t *testing.T) { + msgdesc := &descriptorpb.DescriptorProto{ + Name: proto.String("ExampleMessage"), + Field: []*descriptorpb.FieldDescriptorProto{ + { + Name: proto.String("nested"), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + TypeName: proto.String(".google.protobuf.StringValue"), + Number: proto.Int32(1), + }, + }, + } + meth1 := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("Echo"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + } + meth2 := &descriptorpb.MethodDescriptorProto{ + Name: proto.String("Echo2"), + InputType: proto.String("ExampleMessage"), + OutputType: proto.String("ExampleMessage"), + } + svc1 := &descriptorpb.ServiceDescriptorProto{ + Name: proto.String("ExampleServiceNumberOne"), + Method: []*descriptorpb.MethodDescriptorProto{meth1, meth2}, + } + svc2 := &descriptorpb.ServiceDescriptorProto{ + Name: proto.String("ExampleServiceNumberTwo"), + Method: []*descriptorpb.MethodDescriptorProto{meth1, meth2}, + } + msg := &descriptor.Message{ + DescriptorProto: msgdesc, + } + binding := &descriptor.Binding{ + Index: 1, + PathTmpl: compilePath(t, "/v1/example/echo"), + HTTPMethod: "GET", + PathParams: nil, + Body: nil, + } + file := descriptor.File{ + FileDescriptorProto: &descriptorpb.FileDescriptorProto{ + Name: proto.String("example.proto"), + Package: proto.String("example"), + MessageType: []*descriptorpb.DescriptorProto{msgdesc}, + Service: []*descriptorpb.ServiceDescriptorProto{svc1, svc2}, + }, + GoPkg: descriptor.GoPackage{ + Path: "example.com/path/to/example/example.pb", + Name: "example_pb", + }, + Messages: []*descriptor.Message{msg}, + Services: []*descriptor.Service{ + { + ServiceDescriptorProto: svc1, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth1, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{binding}, + }, + }, + }, + { + ServiceDescriptorProto: svc2, + Methods: []*descriptor.Method{ + { + MethodDescriptorProto: meth2, + RequestType: msg, + ResponseType: msg, + Bindings: []*descriptor.Binding{binding}, + }, + }, + }, + }, + } + _, err := applyTemplate(param{File: crossLinkFixture(&file), RegisterFuncSuffix: "Handler", AllowPatchFeature: true}, descriptor.NewRegistry()) + if err != nil { + t.Errorf("applyTemplate(%#v) failed; want success", file) + return + } +} diff --git a/gateway/protoc-gen-grpc-gateway/main.go b/gateway/protoc-gen-grpc-gateway/main.go index f79141b..5a2c1cb 100644 --- a/gateway/protoc-gen-grpc-gateway/main.go +++ b/gateway/protoc-gen-grpc-gateway/main.go @@ -15,6 +15,8 @@ import ( "strings" "github.com/golang/glog" + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/codegenerator" + // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway/internal/gengateway" @@ -64,6 +66,8 @@ func main() { return err } + codegenerator.SetSupportedFeaturesOnPluginGen(gen) + generator := gengateway.New(reg, *useRequestContext, *registerFuncSuffix, *allowPatchFeature, *standalone) glog.V(1).Infof("Parsing code generator request") diff --git a/gateway/protoc-gen-openapiv2/BUILD.bazel b/gateway/protoc-gen-openapiv2/BUILD.bazel index 5daacad..dda91e1 100644 --- a/gateway/protoc-gen-openapiv2/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/BUILD.bazel @@ -3,28 +3,29 @@ load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test") package(default_visibility = ["//visibility:private"]) go_library( - name = "go_default_library", + name = "protoc-gen-openapiv2_lib", srcs = ["main.go"], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2", deps = [ - "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator:go_default_library", - "//gateway/internal/descriptor:go_default_library", - "//gateway/protoc-gen-openapiv2/internal/genopenapi:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//internal/codegenerator", + "//gateway/internal/descriptor", + "//gateway/protoc-gen-openapiv2/internal/genopenapi", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", + "@com_github_golang_glog//:glog", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/pluginpb", ], ) go_binary( name = "protoc-gen-openapiv2", - embed = [":go_default_library"], + embed = [":protoc-gen-openapiv2_lib"], visibility = ["//visibility:public"], ) go_test( - name = "go_default_test", + name = "protoc-gen-openapiv2_test", size = "small", srcs = ["main_test.go"], - embed = [":go_default_library"], + embed = [":protoc-gen-openapiv2_lib"], ) diff --git a/gateway/protoc-gen-openapiv2/defs.bzl b/gateway/protoc-gen-openapiv2/defs.bzl index 146bc1e..1dbdfc4 100644 --- a/gateway/protoc-gen-openapiv2/defs.bzl +++ b/gateway/protoc-gen-openapiv2/defs.bzl @@ -27,12 +27,12 @@ def _direct_source_infos(proto_info, provided_sources = []): source_root = proto_info.proto_source_root if "." == source_root: - return [struct(file = src, import_path = src.path) for src in proto_info.direct_sources] + return [struct(file = src, import_path = src.path) for src in proto_info.check_deps_sources.to_list()] offset = len(source_root) + 1 # + '/'. infos = [] - for src in proto_info.direct_sources: + for src in proto_info.check_deps_sources.to_list(): # TODO(yannic): Remove this hack when we drop support for Bazel < 1.0. local_offset = offset if src.root.path and not source_root.startswith(src.root.path): @@ -51,10 +51,24 @@ def _run_proto_gen_openapi( transitive_proto_srcs, protoc, protoc_gen_openapiv2, - grpc_api_configuration, single_output, + allow_delete_body, + grpc_api_configuration, json_names_for_fields, - fqn_for_openapi_name): + repeated_path_param_separator, + include_package_in_tags, + fqn_for_openapi_name, + openapi_naming_strategy, + use_go_templates, + disable_default_errors, + enums_as_ints, + omit_enum_default_value, + output_format, + simple_operation_ids, + proto3_optional_nullable, + openapi_configuration, + generate_unbound_methods, + visibility_restriction_selectors): args = actions.args() args.add("--plugin", "protoc-gen-openapiv2=%s" % protoc_gen_openapiv2.path) @@ -67,11 +81,53 @@ def _run_proto_gen_openapi( extra_inputs.append(grpc_api_configuration) args.add("--openapiv2_opt", "grpc_api_configuration=%s" % grpc_api_configuration.path) + if openapi_configuration: + extra_inputs.append(openapi_configuration) + args.add("--openapiv2_opt", "openapi_configuration=%s" % openapi_configuration.path) + if not json_names_for_fields: args.add("--openapiv2_opt", "json_names_for_fields=false") if fqn_for_openapi_name: - args.add("--openapi_opt", "fqn_for_openapi_name=true") + args.add("--openapiv2_opt", "fqn_for_openapi_name=true") + + if openapi_naming_strategy: + args.add("--openapiv2_opt", "openapi_naming_strategy=%s" % openapi_naming_strategy) + + if generate_unbound_methods: + args.add("--openapiv2_opt", "generate_unbound_methods=true") + + if simple_operation_ids: + args.add("--openapiv2_opt", "simple_operation_ids=true") + + if allow_delete_body: + args.add("--openapiv2_opt", "allow_delete_body=true") + + if include_package_in_tags: + args.add("--openapiv2_opt", "include_package_in_tags=true") + + if use_go_templates: + args.add("--openapiv2_opt", "use_go_templates=true") + + if disable_default_errors: + args.add("--openapiv2_opt", "disable_default_errors=true") + + if enums_as_ints: + args.add("--openapiv2_opt", "enums_as_ints=true") + + if omit_enum_default_value: + args.add("--openapiv2_opt", "omit_enum_default_value=true") + + if output_format: + args.add("--openapiv2_opt", "output_format=%s" % output_format) + + if proto3_optional_nullable: + args.add("--openapiv2_opt", "proto3_optional_nullable=true") + + for visibility_restriction_selector in visibility_restriction_selectors: + args.add("--openapiv2_opt", "visibility_restriction_selectors=%s" % visibility_restriction_selector) + + args.add("--openapiv2_opt", "repeated_path_param_separator=%s" % repeated_path_param_separator) proto_file_infos = _direct_source_infos(proto_info) @@ -154,10 +210,24 @@ def _proto_gen_openapi_impl(ctx): ), protoc = ctx.executable._protoc, protoc_gen_openapiv2 = ctx.executable._protoc_gen_openapi, - grpc_api_configuration = ctx.file.grpc_api_configuration, single_output = ctx.attr.single_output, + allow_delete_body = ctx.attr.allow_delete_body, + grpc_api_configuration = ctx.file.grpc_api_configuration, json_names_for_fields = ctx.attr.json_names_for_fields, + repeated_path_param_separator = ctx.attr.repeated_path_param_separator, + include_package_in_tags = ctx.attr.include_package_in_tags, fqn_for_openapi_name = ctx.attr.fqn_for_openapi_name, + openapi_naming_strategy = ctx.attr.openapi_naming_strategy, + use_go_templates = ctx.attr.use_go_templates, + disable_default_errors = ctx.attr.disable_default_errors, + enums_as_ints = ctx.attr.enums_as_ints, + omit_enum_default_value = ctx.attr.omit_enum_default_value, + output_format = ctx.attr.output_format, + simple_operation_ids = ctx.attr.simple_operation_ids, + proto3_optional_nullable = ctx.attr.proto3_optional_nullable, + openapi_configuration = ctx.file.openapi_configuration, + generate_unbound_methods = ctx.attr.generate_unbound_methods, + visibility_restriction_selectors = ctx.attr.visibility_restriction_selectors, ), ), ), @@ -169,21 +239,112 @@ protoc_gen_openapiv2 = rule( mandatory = True, providers = [ProtoInfo], ), - "grpc_api_configuration": attr.label( - allow_single_file = True, + "single_output": attr.bool( + default = False, mandatory = False, + doc = "if set, the rule will generate a single OpenAPI file", ), - "single_output": attr.bool( + "allow_delete_body": attr.bool( default = False, mandatory = False, + doc = "unless set, HTTP DELETE methods may not have a body", + ), + "grpc_api_configuration": attr.label( + allow_single_file = True, + mandatory = False, + doc = "path to file which describes the gRPC API Configuration in YAML format", ), "json_names_for_fields": attr.bool( default = True, mandatory = False, + doc = "if disabled, the original proto name will be used for generating OpenAPI definitions", + ), + "repeated_path_param_separator": attr.string( + default = "csv", + mandatory = False, + values = ["csv", "pipes", "ssv", "tsv"], + doc = "configures how repeated fields should be split." + + " Allowed values are `csv`, `pipes`, `ssv` and `tsv`", + ), + "include_package_in_tags": attr.bool( + default = False, + mandatory = False, + doc = "if unset, the gRPC service name is added to the `Tags`" + + " field of each operation. If set and the `package` directive" + + " is shown in the proto file, the package name will be " + + " prepended to the service name", ), "fqn_for_openapi_name": attr.bool( default = False, mandatory = False, + doc = "if set, the object's OpenAPI names will use the fully" + + " qualified names from the proto definition" + + " (ie my.package.MyMessage.MyInnerMessage", + ), + "openapi_naming_strategy": attr.string( + default = "", + mandatory = False, + values = ["", "simple", "legacy", "fqn"], + doc = "configures how OpenAPI names are determined." + + " Allowed values are `` (empty), `simple`, `legacy` and `fqn`." + + " If unset, either `legacy` or `fqn` are selected, depending" + + " on the value of the `fqn_for_openapi_name` setting", + ), + "use_go_templates": attr.bool( + default = False, + mandatory = False, + doc = "if set, you can use Go templates in protofile comments", + ), + "disable_default_errors": attr.bool( + default = False, + mandatory = False, + doc = "if set, disables generation of default errors." + + " This is useful if you have defined custom error handling", + ), + "enums_as_ints": attr.bool( + default = False, + mandatory = False, + doc = "whether to render enum values as integers, as opposed to string values", + ), + "omit_enum_default_value": attr.bool( + default = False, + mandatory = False, + doc = "if set, omit default enum value", + ), + "output_format": attr.string( + default = "json", + mandatory = False, + values = ["json", "yaml"], + doc = "output content format. Allowed values are: `json`, `yaml`", + ), + "simple_operation_ids": attr.bool( + default = False, + mandatory = False, + doc = "whether to remove the service prefix in the operationID" + + " generation. Can introduce duplicate operationIDs, use with caution.", + ), + "proto3_optional_nullable": attr.bool( + default = False, + mandatory = False, + doc = "whether Proto3 Optional fields should be marked as x-nullable", + ), + "openapi_configuration": attr.label( + allow_single_file = True, + mandatory = False, + doc = "path to file which describes the OpenAPI Configuration in YAML format", + ), + "generate_unbound_methods": attr.bool( + default = False, + mandatory = False, + doc = "generate swagger metadata even for RPC methods that have" + + " no HttpRule annotation", + ), + "visibility_restriction_selectors": attr.string_list( + mandatory = False, + doc = "list of `google.api.VisibilityRule` visibility labels to include" + + " in the generated output when a visibility annotation is defined." + + " Repeat this option to supply multiple values. Elements without" + + " visibility annotations are unaffected by this setting.", ), "_protoc": attr.label( default = "@com_google_protobuf//:protoc", diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel b/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel index 67c49ae..90b780b 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel @@ -3,54 +3,71 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "genopenapi", srcs = [ "doc.go", + "format.go", "generator.go", "helpers.go", "helpers_go111_old.go", + "naming.go", "template.go", "types.go", ], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi", deps = [ - "//gateway/internal/casing:go_default_library", - "//gateway/internal/descriptor:go_default_library", - "//gateway/internal/generator:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", - "//httpoptions:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//gateway/internal/casing", + "//gateway/internal/descriptor", + "//gateway/internal/generator", + "//gateway/protoc-gen-openapiv2/options", + "//httpoptions", + "@com_github_golang_glog//:glog", "@com_github_golang_protobuf//descriptor:go_default_library_gen", + "@go_googleapis//google/api:annotations_go_proto", + "@go_googleapis//google/api:visibility_go_proto", "@go_googleapis//google/rpc:status_go_proto", + "@in_gopkg_yaml_v2//:yaml_v2", "@io_bazel_rules_go//proto/wkt:any_go_proto", - "@io_bazel_rules_go//proto/wkt:struct_go_proto", - "@org_golang_google_protobuf//encoding/protojson:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//types/descriptorpb:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "@org_golang_google_protobuf//encoding/protojson", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//types/descriptorpb", + "@org_golang_google_protobuf//types/known/structpb", + "@org_golang_google_protobuf//types/pluginpb", ], ) go_test( - name = "go_default_test", + name = "genopenapi_test", size = "small", - srcs = ["template_test.go"], - embed = [":go_default_library"], + srcs = [ + "cycle_test.go", + ], + embed = [":genopenapi"], deps = [ - "//gateway/internal/descriptor:go_default_library", - "//gateway/internal/descriptor/openapiconfig:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", - "//gateway/protoc-gen-openapiv2/options:go_default_library", - "//gateway/runtime:go_default_library", - "@com_github_google_go_cmp//cmp:go_default_library", + "//gateway/internal/descriptor", + "//gateway/internal/descriptor/openapiconfig", + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule", + "//gateway/protoc-gen-openapiv2/options", + "//gateway/runtime", + "@com_github_google_go_cmp//cmp", + "@go_googleapis//google/api:annotations_go_proto", + "@go_googleapis//google/api:visibility_go_proto", + "@in_gopkg_yaml_v2//:yaml_v2", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//reflect/protodesc:go_default_library", - "@org_golang_google_protobuf//types/descriptorpb:go_default_library", - "@org_golang_google_protobuf//types/known/durationpb:go_default_library", - "@org_golang_google_protobuf//types/known/structpb:go_default_library", - "@org_golang_google_protobuf//types/known/timestamppb:go_default_library", - "@org_golang_google_protobuf//types/known/wrapperspb:go_default_library", - "@org_golang_google_protobuf//types/pluginpb:go_default_library", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//reflect/protodesc", + "@org_golang_google_protobuf//types/descriptorpb", + "@org_golang_google_protobuf//types/known/anypb", + "@org_golang_google_protobuf//types/known/durationpb", + "@org_golang_google_protobuf//types/known/structpb", + "@org_golang_google_protobuf//types/known/timestamppb", + "@org_golang_google_protobuf//types/known/wrapperspb", + "@org_golang_google_protobuf//types/pluginpb", ], ) + +alias( + name = "go_default_library", + actual = ":genopenapi", + visibility = ["//protoc-gen-openapiv2:__subpackages__"], +) diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/cycle_test.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/cycle_test.go new file mode 100644 index 0000000..8861315 --- /dev/null +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/cycle_test.go @@ -0,0 +1,41 @@ +package genopenapi + +import ( + "testing" +) + +func TestCycle(t *testing.T) { + for _, tt := range []struct { + max int + attempt int + e bool + }{ + { + max: 3, + attempt: 3, + e: true, + }, + { + max: 5, + attempt: 6, + }, + { + max: 1000, + attempt: 1001, + }, + } { + + c := newCycleChecker(tt.max) + var final bool + for i := 0; i < tt.attempt; i++ { + final = c.Check("a") + if !final { + break + } + } + + if final != tt.e { + t.Errorf("got: %t wanted: %t", final, tt.e) + } + } +} diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/format.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/format.go new file mode 100644 index 0000000..e957acc --- /dev/null +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/format.go @@ -0,0 +1,43 @@ +package genopenapi + +import ( + "encoding/json" + "errors" + "io" + + "gopkg.in/yaml.v2" +) + +type Format string + +const ( + FormatJSON Format = "json" + FormatYAML Format = "yaml" +) + +type ContentEncoder interface { + Encode(v interface{}) (err error) +} + +func (f Format) Validate() error { + switch f { + case FormatJSON, FormatYAML: + return nil + default: + return errors.New("unknown format: " + string(f)) + } +} + +func (f Format) NewEncoder(w io.Writer) (ContentEncoder, error) { + switch f { + case FormatYAML: + return yaml.NewEncoder(w), nil + case FormatJSON: + enc := json.NewEncoder(w) + enc.SetIndent("", " ") + + return enc, nil + default: + return nil, errors.New("unknown format: " + string(f)) + } +} diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go index f3b7a7b..ab67212 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/generator.go @@ -22,7 +22,7 @@ import ( "google.golang.org/protobuf/types/descriptorpb" "google.golang.org/protobuf/types/pluginpb" - //lint:ignore SA1019 known issue, will be replaced when possible + //nolint:staticcheck // Known issue, will be replaced when possible legacydescriptor "github.com/golang/protobuf/descriptor" ) @@ -31,7 +31,8 @@ var ( ) type generator struct { - reg *descriptor.Registry + reg *descriptor.Registry + format Format } type wrapper struct { @@ -39,9 +40,17 @@ type wrapper struct { swagger *openapiSwaggerObject } +type GeneratorOptions struct { + Registry *descriptor.Registry + RecursiveDepth int +} + // New returns a new generator which generates grpc gateway files. -func New(reg *descriptor.Registry) gen.Generator { - return &generator{reg: reg} +func New(reg *descriptor.Registry, format Format) gen.Generator { + return &generator{ + reg: reg, + format: format, + } } // Merge a lot of OpenAPI file (wrapper) to single one OpenAPI file @@ -141,21 +150,25 @@ func extensionMarshalJSON(so interface{}, extensions []extension) ([]byte, error } // encodeOpenAPI converts OpenAPI file obj to pluginpb.CodeGeneratorResponse_File -func encodeOpenAPI(file *wrapper) (*descriptor.ResponseFile, error) { - var formatted bytes.Buffer - enc := json.NewEncoder(&formatted) - enc.SetIndent("", " ") +func encodeOpenAPI(file *wrapper, format Format) (*descriptor.ResponseFile, error) { + var contentBuf bytes.Buffer + enc, err := format.NewEncoder(&contentBuf) + if err != nil { + return nil, err + } + if err := enc.Encode(*file.swagger); err != nil { return nil, err } + name := file.fileName ext := filepath.Ext(name) base := strings.TrimSuffix(name, ext) - output := fmt.Sprintf("%s.swagger.json", base) + output := fmt.Sprintf("%s.swagger."+string(format), base) return &descriptor.ResponseFile{ CodeGeneratorResponse_File: &pluginpb.CodeGeneratorResponse_File{ Name: proto.String(output), - Content: proto.String(formatted.String()), + Content: proto.String(contentBuf.String()), }, }, nil } @@ -205,7 +218,7 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*descriptor.Response if g.reg.IsAllowMerge() { targetOpenAPI := mergeTargetFile(openapis, g.reg.GetMergeFileName()) - f, err := encodeOpenAPI(targetOpenAPI) + f, err := encodeOpenAPI(targetOpenAPI, g.format) if err != nil { return nil, fmt.Errorf("failed to encode OpenAPI for %s: %s", g.reg.GetMergeFileName(), err) } @@ -213,7 +226,7 @@ func (g *generator) Generate(targets []*descriptor.File) ([]*descriptor.Response glog.V(1).Infof("New OpenAPI file will emit") } else { for _, file := range openapis { - f, err := encodeOpenAPI(file) + f, err := encodeOpenAPI(file, g.format) if err != nil { return nil, fmt.Errorf("failed to encode OpenAPI for %s: %s", file.fileName, err) } diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/naming.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/naming.go new file mode 100644 index 0000000..338ea2d --- /dev/null +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/naming.go @@ -0,0 +1,110 @@ +package genopenapi + +import ( + "reflect" + "strings" +) + +// LookupNamingStrategy looks up the given naming strategy and returns the naming +// strategy function for it. The naming strategy function takes in the list of all +// fully-qualified proto message names, and returns a mapping from fully-qualified +// name to OpenAPI name. +func LookupNamingStrategy(strategyName string) func([]string) map[string]string { + switch strings.ToLower(strategyName) { + case "fqn": + return resolveNamesFQN + case "legacy": + return resolveNamesLegacy + case "simple": + return resolveNamesSimple + } + return nil +} + +// resolveNamesFQN uses the fully-qualified proto message name as the +// OpenAPI name, stripping the leading dot. +func resolveNamesFQN(messages []string) map[string]string { + uniqueNames := make(map[string]string, len(messages)) + for _, p := range messages { + // strip leading dot from proto fqn + uniqueNames[p] = p[1:] + } + return uniqueNames +} + +// resolveNamesLegacy takes the names of all proto messages and generates unique references by +// applying the legacy heuristics for deriving unique names: starting from the bottom of the name hierarchy, it +// determines the minimum number of components necessary to yield a unique name, adds one +// to that number, and then concatenates those last components with no separator in between +// to form a unique name. +// +// E.g., if the fully qualified name is `.a.b.C.D`, and there are other messages with fully +// qualified names ending in `.D` but not in `.C.D`, it assigns the unique name `bCD`. +func resolveNamesLegacy(messages []string) map[string]string { + return resolveNamesUniqueWithContext(messages, 1, "") +} + +// resolveNamesSimple takes the names of all proto messages and generates unique references by using a simple +// heuristic: starting from the bottom of the name hierarchy, it determines the minimum +// number of components necessary to yield a unique name, and then concatenates those last +// components with a "." separator in between to form a unique name. +// +// E.g., if the fully qualified name is `.a.b.C.D`, and there are other messages with +// fully qualified names ending in `.D` but not in `.C.D`, it assigns the unique name `C.D`. +func resolveNamesSimple(messages []string) map[string]string { + return resolveNamesUniqueWithContext(messages, 0, ".") +} + +// Take the names of every proto message and generates a unique reference by: +// first, separating each message name into its components by splitting at dots. Then, +// take the shortest suffix slice from each components slice that is unique among all +// messages, and convert it into a component name by taking extraContext additional +// components into consideration and joining all components with componentSeparator. +func resolveNamesUniqueWithContext(messages []string, extraContext int, componentSeparator string) map[string]string { + packagesByDepth := make(map[int][][]string) + uniqueNames := make(map[string]string) + + hierarchy := func(pkg string) []string { + return strings.Split(pkg, ".") + } + + for _, p := range messages { + h := hierarchy(p) + for depth := range h { + if _, ok := packagesByDepth[depth]; !ok { + packagesByDepth[depth] = make([][]string, 0) + } + packagesByDepth[depth] = append(packagesByDepth[depth], h[len(h)-depth:]) + } + } + + count := func(list [][]string, item []string) int { + i := 0 + for _, element := range list { + if reflect.DeepEqual(element, item) { + i++ + } + } + return i + } + + for _, p := range messages { + h := hierarchy(p) + depth := 0 + for ; depth < len(h); depth++ { + // depth + extraContext > 0 ensures that we only break for values of depth when the + // resulting slice of name components is non-empty. Otherwise, we would return the + // empty string as the concise unique name is len(messages) == 1 (which is + // technically correct). + if depth+extraContext > 0 && count(packagesByDepth[depth], h[len(h)-depth:]) == 1 { + break + } + } + start := len(h) - depth - extraContext + if start < 0 { + start = 0 + } + uniqueNames[p] = strings.Join(h[start:], componentSeparator) + } + return uniqueNames +} diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go index 4defa99..5fccfa2 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/template.go @@ -5,6 +5,8 @@ import ( "encoding/json" "fmt" "io/ioutil" + "math" + "net/textproto" "os" "reflect" "regexp" @@ -13,9 +15,9 @@ import ( "strings" "sync" "text/template" + "time" "github.com/golang/glog" - structpb "github.com/golang/protobuf/ptypes/struct" // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/casing" "github.com/binchencoder/ease-gateway/gateway/internal/casing" @@ -23,22 +25,34 @@ import ( "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" // openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" + "google.golang.org/genproto/googleapis/api/annotations" + "google.golang.org/genproto/googleapis/api/visibility" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/descriptorpb" + "google.golang.org/protobuf/types/known/structpb" + options "github.com/binchencoder/ease-gateway/httpoptions" ) +// The OpenAPI specification does not allow for more than one endpoint with the same HTTP method and path. +// This prevents multiple gRPC service methods from sharing the same stripped version of the path and method. +// For example: `GET /v1/{name=organizations/*}/roles` and `GET /v1/{name=users/*}/roles` both get stripped to `GET /v1/{name}/roles`. +// We must make the URL unique by adding a suffix and an incrementing index to each path parameter +// to differentiate the endpoints. +// Since path parameter names do not affect the request contents (i.e. they're replaced in the path) +// this will be hidden from the real grpc gateway consumer. +const pathParamUniqueSuffixDeliminator = "_" + +const paragraphDeliminator = "\n\n" + // wktSchemas are the schemas of well-known-types. // The schemas must match with the behavior of the JSON unmarshaler in // https://github.com/protocolbuffers/protobuf-go/blob/v1.25.0/encoding/protojson/well_known_types.go var wktSchemas = map[string]schemaCore{ ".google.protobuf.FieldMask": { - Type: "array", - Items: (*openapiItemsObject)(&schemaCore{ - Type: "string", - }), + Type: "string", }, ".google.protobuf.Timestamp": { Type: "string", @@ -99,24 +113,38 @@ var wktSchemas = map[string]schemaCore{ }, } -func listEnumNames(enum *descriptor.Enum) (names []string) { +func listEnumNames(reg *descriptor.Registry, enum *descriptor.Enum) (names []string) { for _, value := range enum.GetValue() { + if !isVisible(getEnumValueVisibilityOption(value), reg) { + continue + } + if reg.GetOmitEnumDefaultValue() && value.GetNumber() == 0 { + continue + } names = append(names, value.GetName()) } return names } -func listEnumNumbers(enum *descriptor.Enum) (numbers []string) { +func listEnumNumbers(reg *descriptor.Registry, enum *descriptor.Enum) (numbers []string) { for _, value := range enum.GetValue() { + if reg.GetOmitEnumDefaultValue() && value.GetNumber() == 0 { + continue + } + if !isVisible(getEnumValueVisibilityOption(value), reg) { + continue + } numbers = append(numbers, strconv.Itoa(int(value.GetNumber()))) } return } -func getEnumDefault(enum *descriptor.Enum) string { - for _, value := range enum.GetValue() { - if value.GetNumber() == 0 { - return value.GetName() +func getEnumDefault(reg *descriptor.Registry, enum *descriptor.Enum) string { + if !reg.GetOmitEnumDefaultValue() { + for _, value := range enum.GetValue() { + if value.GetNumber() == 0 { + return value.GetName() + } } } return "" @@ -125,7 +153,11 @@ func getEnumDefault(enum *descriptor.Enum) string { // messageToQueryParameters converts a message to a list of OpenAPI query parameters. func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body) (params []openapiParameterObject, err error) { for _, field := range message.Fields { - p, err := queryParams(message, field, "", reg, pathParams, body) + if !isVisible(getFieldVisibilityOption(field), reg) { + continue + } + + p, err := queryParams(message, field, "", reg, pathParams, body, reg.GetRecursiveDepth()) if err != nil { return nil, err } @@ -135,17 +167,64 @@ func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Regis } // queryParams converts a field to a list of OpenAPI query parameters recursively through the use of nestedQueryParams. -func queryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body) (params []openapiParameterObject, err error) { - return nestedQueryParams(message, field, prefix, reg, pathParams, body, map[string]bool{}) +func queryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body, recursiveCount int) (params []openapiParameterObject, err error) { + return nestedQueryParams(message, field, prefix, reg, pathParams, body, newCycleChecker(recursiveCount)) +} + +type cycleChecker struct { + m map[string]int + count int +} + +func newCycleChecker(recursive int) *cycleChecker { + return &cycleChecker{ + m: make(map[string]int), + count: recursive, + } +} + +// Check returns whether name is still within recursion +// toleration +func (c *cycleChecker) Check(name string) bool { + count, ok := c.m[name] + count = count + 1 + isCycle := count > c.count + + if isCycle { + return false + } + + // provision map entry if not available + if !ok { + c.m[name] = 1 + return true + } + + c.m[name] = count + + return true +} + +func (c *cycleChecker) Branch() *cycleChecker { + copy := &cycleChecker{ + count: c.count, + m: map[string]int{}, + } + + for k, v := range c.m { + copy.m[k] = v + } + + return copy } // nestedQueryParams converts a field to a list of OpenAPI query parameters recursively. // This function is a helper function for queryParams, that keeps track of cyclical message references // through the use of -// touched map[string]bool -// If a cycle is discovered, an error is returned, as cyclical data structures aren't allowed +// touched map[string]int +// If a cycle is discovered, an error is returned, as cyclical data structures are dangerous // in query parameters. -func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body, touchedIn map[string]bool) (params []openapiParameterObject, err error) { +func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, prefix string, reg *descriptor.Registry, pathParams []descriptor.Parameter, body *descriptor.Body, cycle *cycleChecker) (params []openapiParameterObject, err error) { // make sure the parameter is not already listed as a path parameter for _, pathParam := range pathParams { if pathParam.Target == field { @@ -181,15 +260,12 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre if items != nil && (items.Type == "" || items.Type == "object") && !isEnum { return nil, nil // TODO: currently, mapping object in query parameter is not supported } - desc := schema.Description - if schema.Title != "" { // merge title because title of parameter object will be ignored - desc = strings.TrimSpace(schema.Title + ". " + schema.Description) - } + desc := mergeDescription(schema) // verify if the field is required required := false for _, fieldName := range schema.Required { - if fieldName == field.GetName() { + if fieldName == reg.FieldName(field) { required = true break } @@ -202,17 +278,14 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre Type: schema.Type, Items: schema.Items, Format: schema.Format, + Pattern: schema.Pattern, Required: required, } if param.Type == "array" { param.CollectionFormat = "multi" } - if reg.GetUseJSONNamesForFields() { - param.Name = prefix + field.GetJsonName() - } else { - param.Name = prefix + field.GetName() - } + param.Name = prefix + reg.FieldName(field) if isEnum { enum, err := reg.LookupEnum("", fieldType) @@ -222,20 +295,22 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre if items != nil { // array param.Items = &openapiItemsObject{ Type: "string", - Enum: listEnumNames(enum), + Enum: listEnumNames(reg, enum), } if reg.GetEnumsAsInts() { param.Items.Type = "integer" - param.Items.Enum = listEnumNumbers(enum) + param.Items.Enum = listEnumNumbers(reg, enum) } } else { param.Type = "string" - param.Enum = listEnumNames(enum) - param.Default = getEnumDefault(enum) + param.Enum = listEnumNames(reg, enum) + param.Default = getEnumDefault(reg, enum) if reg.GetEnumsAsInts() { param.Type = "integer" - param.Enum = listEnumNumbers(enum) - param.Default = "0" + param.Enum = listEnumNumbers(reg, enum) + if !reg.GetOmitEnumDefaultValue() { + param.Default = "0" + } } } valueComments := enumValueProtoComments(reg, enum) @@ -253,27 +328,22 @@ func nestedQueryParams(message *descriptor.Message, field *descriptor.Field, pre } // Check for cyclical message reference: - isCycle := touchedIn[*msg.Name] - if isCycle { - return nil, fmt.Errorf("recursive types are not allowed for query parameters, cycle found on %q", fieldType) + isOK := cycle.Check(*msg.Name) + if !isOK { + return nil, fmt.Errorf("exceeded recursive count (%d) for query parameter %q", cycle.count, fieldType) } // Construct a new map with the message name so a cycle further down the recursive path can be detected. // Do not keep anything in the original touched reference and do not pass that reference along. This will // prevent clobbering adjacent records while recursing. - touchedOut := make(map[string]bool) - for k, v := range touchedIn { - touchedOut[k] = v - } - touchedOut[*msg.Name] = true + touchedOut := cycle.Branch() for _, nestedField := range msg.Fields { - var fieldName string - if reg.GetUseJSONNamesForFields() { - fieldName = field.GetJsonName() - } else { - fieldName = field.GetName() + if !isVisible(getFieldVisibilityOption(nestedField), reg) { + continue } + + fieldName := reg.FieldName(field) p, err := nestedQueryParams(msg, nestedField, prefix+fieldName+".", reg, pathParams, body, touchedOut) if err != nil { return nil, err @@ -321,6 +391,10 @@ func findServicesMessagesAndEnumerations(s []*descriptor.Service, reg *descripto func findNestedMessagesAndEnumerations(message *descriptor.Message, reg *descriptor.Registry, m messageMap, e enumMap) { // Iterate over all the fields that for _, t := range message.Fields { + if !isVisible(getFieldVisibilityOption(t), reg) { + continue + } + fieldType := t.GetTypeName() // If the type is an empty string then it is a proto primitive if fieldType != "" { @@ -346,11 +420,153 @@ func skipRenderingRef(refName string) bool { return ok } -func renderMessagesAsDefinition(messages messageMap, d openapiDefinitionsObject, reg *descriptor.Registry, customRefs refMap) { +func renderMessageAsDefinition(msg *descriptor.Message, reg *descriptor.Registry, customRefs refMap, pathParams []descriptor.Parameter) (openapiSchemaObject, error) { + schema := openapiSchemaObject{ + schemaCore: schemaCore{ + Type: "object", + }, + } + msgComments := protoComments(reg, msg.File, msg.Outers, "MessageType", int32(msg.Index)) + if err := updateOpenAPIDataFromComments(reg, &schema, msg, msgComments, false); err != nil { + return openapiSchemaObject{}, err + } + opts, err := getMessageOpenAPIOption(reg, msg) + if err != nil { + return openapiSchemaObject{}, err + } + if opts != nil { + protoSchema := openapiSchemaFromProtoSchema(opts, reg, customRefs, msg) + + // Warning: Make sure not to overwrite any fields already set on the schema type. + schema.ExternalDocs = protoSchema.ExternalDocs + schema.ReadOnly = protoSchema.ReadOnly + schema.MultipleOf = protoSchema.MultipleOf + schema.Maximum = protoSchema.Maximum + schema.ExclusiveMaximum = protoSchema.ExclusiveMaximum + schema.Minimum = protoSchema.Minimum + schema.ExclusiveMinimum = protoSchema.ExclusiveMinimum + schema.MaxLength = protoSchema.MaxLength + schema.MinLength = protoSchema.MinLength + schema.Pattern = protoSchema.Pattern + schema.Default = protoSchema.Default + schema.MaxItems = protoSchema.MaxItems + schema.MinItems = protoSchema.MinItems + schema.UniqueItems = protoSchema.UniqueItems + schema.MaxProperties = protoSchema.MaxProperties + schema.MinProperties = protoSchema.MinProperties + schema.Required = protoSchema.Required + schema.XNullable = protoSchema.XNullable + if protoSchema.schemaCore.Type != "" || protoSchema.schemaCore.Ref != "" { + schema.schemaCore = protoSchema.schemaCore + } + if protoSchema.Title != "" { + schema.Title = protoSchema.Title + } + if protoSchema.Description != "" { + schema.Description = protoSchema.Description + } + if protoSchema.Example != nil { + schema.Example = protoSchema.Example + } + } + + schema.Required = filterOutExcludedFields(schema.Required, pathParams) + + for _, f := range msg.Fields { + if !isVisible(getFieldVisibilityOption(f), reg) { + continue + } + + if shouldExcludeField(f.GetName(), pathParams) { + continue + } + subPathParams := subPathParams(f.GetName(), pathParams) + fieldSchema, err := renderFieldAsDefinition(f, reg, customRefs, subPathParams) + if err != nil { + return openapiSchemaObject{}, err + } + comments := fieldProtoComments(reg, msg, f) + if err := updateOpenAPIDataFromComments(reg, &fieldSchema, f, comments, false); err != nil { + return openapiSchemaObject{}, err + } + + if requiredIdx := find(schema.Required, *f.Name); requiredIdx != -1 && reg.GetUseJSONNamesForFields() { + schema.Required[requiredIdx] = f.GetJsonName() + } + + if fieldSchema.Required != nil { + schema.Required = append(schema.Required, fieldSchema.Required...) + } + + kv := keyVal{Value: fieldSchema} + kv.Key = reg.FieldName(f) + if schema.Properties == nil { + schema.Properties = &openapiSchemaObjectProperties{} + } + *schema.Properties = append(*schema.Properties, kv) + } + + if msg.FQMN() == ".google.protobuf.Any" { + transformAnyForJSON(&schema, reg.GetUseJSONNamesForFields()) + } + + return schema, nil +} + +func renderFieldAsDefinition(f *descriptor.Field, reg *descriptor.Registry, refs refMap, pathParams []descriptor.Parameter) (openapiSchemaObject, error) { + if len(pathParams) == 0 { + return schemaOfField(f, reg, refs), nil + } + location := "" + if ix := strings.LastIndex(f.Message.FQMN(), "."); ix > 0 { + location = f.Message.FQMN()[0:ix] + } + msg, err := reg.LookupMsg(location, f.GetTypeName()) + if err != nil { + return openapiSchemaObject{}, err + } + schema, err := renderMessageAsDefinition(msg, reg, refs, pathParams) + if err != nil { + return openapiSchemaObject{}, err + } + comments := fieldProtoComments(reg, f.Message, f) + if len(comments) > 0 { + // Use title and description from field instead of nested message if present. + paragraphs := strings.Split(comments, paragraphDeliminator) + schema.Title = strings.TrimSpace(paragraphs[0]) + schema.Description = strings.TrimSpace(strings.Join(paragraphs[1:], paragraphDeliminator)) + } + return schema, nil +} + +// transformAnyForJSON should be called when the schema object represents a google.protobuf.Any, and will replace the +// Properties slice with a single value for '@type'. We mutate the incorrectly named field so that we inherit the same +// documentation as specified on the original field in the protobuf descriptors. +func transformAnyForJSON(schema *openapiSchemaObject, useJSONNames bool) { + var typeFieldName string + if useJSONNames { + typeFieldName = "typeUrl" + } else { + typeFieldName = "type_url" + } + + for _, property := range *schema.Properties { + if property.Key == typeFieldName { + schema.AdditionalProperties = &openapiSchemaObject{} + schema.Properties = &openapiSchemaObjectProperties{keyVal{ + Key: "@type", + Value: property.Value, + }} + break + } + } +} + +func renderMessagesAsDefinition(messages messageMap, d openapiDefinitionsObject, reg *descriptor.Registry, customRefs refMap, pathParams []descriptor.Parameter) error { for name, msg := range messages { swgName, ok := fullyQualifiedNameToOpenAPIName(msg.FQMN(), reg) if !ok { - panic(fmt.Sprintf("can't resolve OpenAPI name from '%v'", msg.FQMN())) + return fmt.Errorf("can't resolve OpenAPI name from '%v'", msg.FQMN()) } if skipRenderingRef(name) { continue @@ -359,74 +575,55 @@ func renderMessagesAsDefinition(messages messageMap, d openapiDefinitionsObject, if opt := msg.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry { continue } - schema := openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "object", - }, - } - msgComments := protoComments(reg, msg.File, msg.Outers, "MessageType", int32(msg.Index)) - if err := updateOpenAPIDataFromComments(reg, &schema, msg, msgComments, false); err != nil { - panic(err) - } - opts, err := getMessageOpenAPIOption(reg, msg) + var err error + d[swgName], err = renderMessageAsDefinition(msg, reg, customRefs, pathParams) if err != nil { - panic(err) + return err } - if opts != nil { - protoSchema := openapiSchemaFromProtoSchema(opts, reg, customRefs, msg) - - // Warning: Make sure not to overwrite any fields already set on the schema type. - schema.ExternalDocs = protoSchema.ExternalDocs - schema.ReadOnly = protoSchema.ReadOnly - schema.MultipleOf = protoSchema.MultipleOf - schema.Maximum = protoSchema.Maximum - schema.ExclusiveMaximum = protoSchema.ExclusiveMaximum - schema.Minimum = protoSchema.Minimum - schema.ExclusiveMinimum = protoSchema.ExclusiveMinimum - schema.MaxLength = protoSchema.MaxLength - schema.MinLength = protoSchema.MinLength - schema.Pattern = protoSchema.Pattern - schema.Default = protoSchema.Default - schema.MaxItems = protoSchema.MaxItems - schema.MinItems = protoSchema.MinItems - schema.UniqueItems = protoSchema.UniqueItems - schema.MaxProperties = protoSchema.MaxProperties - schema.MinProperties = protoSchema.MinProperties - schema.Required = protoSchema.Required - if protoSchema.schemaCore.Type != "" || protoSchema.schemaCore.Ref != "" { - schema.schemaCore = protoSchema.schemaCore - } - if protoSchema.Title != "" { - schema.Title = protoSchema.Title - } - if protoSchema.Description != "" { - schema.Description = protoSchema.Description - } - if protoSchema.Example != nil { - schema.Example = protoSchema.Example - } + } + return nil +} + +// isVisible checks if a field/RPC is visible based on the visibility restriction +// combined with the `visibility_restriction_selectors`. +// Elements with an overlap on `visibility_restriction_selectors` are visible, those without are not visible. +// Elements without `google.api.VisibilityRule` annotations entirely are always visible. +func isVisible(r *visibility.VisibilityRule, reg *descriptor.Registry) bool { + if r == nil { + return true + } + + restrictions := strings.Split(strings.TrimSpace(r.Restriction), ",") + // No restrictions results in the element always being visible + if len(restrictions) == 0 { + return true + } + + for _, restriction := range restrictions { + if reg.GetVisibilityRestrictionSelectors()[strings.TrimSpace(restriction)] { + return true } + } - for _, f := range msg.Fields { - fieldValue := schemaOfField(f, reg, customRefs) - comments := fieldProtoComments(reg, msg, f) - if err := updateOpenAPIDataFromComments(reg, &fieldValue, f, comments, false); err != nil { - panic(err) - } + return false +} - kv := keyVal{Value: fieldValue} - if reg.GetUseJSONNamesForFields() { - kv.Key = f.GetJsonName() - } else { - kv.Key = f.GetName() - } - if schema.Properties == nil { - schema.Properties = &openapiSchemaObjectProperties{} - } - *schema.Properties = append(*schema.Properties, kv) +func shouldExcludeField(name string, excluded []descriptor.Parameter) bool { + for _, p := range excluded { + if len(p.FieldPath) == 1 && name == p.FieldPath[0].Name { + return true + } + } + return false +} +func filterOutExcludedFields(fields []string, excluded []descriptor.Parameter) []string { + var filtered []string + for _, f := range fields { + if !shouldExcludeField(f, excluded) { + filtered = append(filtered, f) } - d[swgName] = schema } + return filtered } // schemaOfField returns a OpenAPI Schema Object for a protobuf field. @@ -442,7 +639,11 @@ func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) o ) fd := f.FieldDescriptorProto - if m, err := reg.LookupMsg("", f.GetTypeName()); err == nil { + location := "" + if ix := strings.LastIndex(f.Message.FQMN(), "."); ix > 0 { + location = f.Message.FQMN()[0:ix] + } + if m, err := reg.LookupMsg(location, f.GetTypeName()); err == nil { if opt := m.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry { fd = m.GetField()[1] aggregate = object @@ -515,6 +716,14 @@ func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) o updateswaggerObjectFromJSONSchema(&ret, j, reg, f) } + if j, err := getFieldBehaviorOption(reg, f); err == nil { + updateSwaggerObjectFromFieldBehavior(&ret, j, reg, f) + } + + if reg.GetProto3OptionalNullable() && f.GetProto3Optional() { + ret.XNullable = true + } + return ret } @@ -587,8 +796,8 @@ func renderEnumerationsAsDefinition(enums enumMap, d openapiDefinitionsObject, r enumComments := protoComments(reg, enum.File, enum.Outers, "EnumType", int32(enum.Index)) // it may be necessary to sort the result of the GetValue function. - enumNames := listEnumNames(enum) - defaultValue := getEnumDefault(enum) + enumNames := listEnumNames(reg, enum) + defaultValue := getEnumDefault(reg, enum) valueComments := enumValueProtoComments(reg, enum) if valueComments != "" { enumComments = strings.TrimLeft(enumComments+"\n\n "+valueComments, "\n") @@ -604,7 +813,7 @@ func renderEnumerationsAsDefinition(enums enumMap, d openapiDefinitionsObject, r enumSchemaObject.Type = "integer" enumSchemaObject.Format = "int32" enumSchemaObject.Default = "0" - enumSchemaObject.Enum = listEnumNumbers(enum) + enumSchemaObject.Enum = listEnumNumbers(reg, enum) } if err := updateOpenAPIDataFromComments(reg, &enumSchemaObject, enum, enumComments, false); err != nil { panic(err) @@ -623,7 +832,7 @@ func fullyQualifiedNameToOpenAPIName(fqn string, reg *descriptor.Registry) (stri ret, ok := mapping[fqn] return ret, ok } - mapping := resolveFullyQualifiedNameToOpenAPINames(append(reg.GetAllFQMNs(), reg.GetAllFQENs()...), reg.GetUseFQNForOpenAPIName()) + mapping := resolveFullyQualifiedNameToOpenAPINames(append(reg.GetAllFQMNs(), reg.GetAllFQENs()...), reg.GetOpenAPINamingStrategy()) registriesSeen[reg] = mapping ret, ok := mapping[fqn] return ret, ok @@ -648,65 +857,20 @@ func lookupMsgAndOpenAPIName(location, name string, reg *descriptor.Registry) (* var registriesSeen = map[*descriptor.Registry]map[string]string{} var registriesSeenMutex sync.Mutex -// Take the names of every proto and "uniq-ify" them. The idea is to produce a -// set of names that meet a couple of conditions. They must be stable, they -// must be unique, and they must be shorter than the FQN. -// -// This likely could be made better. This will always generate the same names -// but may not always produce optimal names. This is a reasonably close -// approximation of what they should look like in most cases. -func resolveFullyQualifiedNameToOpenAPINames(messages []string, useFQNForOpenAPIName bool) map[string]string { - packagesByDepth := make(map[int][][]string) - uniqueNames := make(map[string]string) - - hierarchy := func(pkg string) []string { - return strings.Split(pkg, ".") - } - - for _, p := range messages { - h := hierarchy(p) - for depth := range h { - if _, ok := packagesByDepth[depth]; !ok { - packagesByDepth[depth] = make([][]string, 0) - } - packagesByDepth[depth] = append(packagesByDepth[depth], h[len(h)-depth:]) - } - } - - count := func(list [][]string, item []string) int { - i := 0 - for _, element := range list { - if reflect.DeepEqual(element, item) { - i++ - } - } - return i - } - - for _, p := range messages { - if useFQNForOpenAPIName { - // strip leading dot from proto fqn - uniqueNames[p] = p[1:] - } else { - h := hierarchy(p) - for depth := 0; depth < len(h); depth++ { - if count(packagesByDepth[depth], h[len(h)-depth:]) == 1 { - uniqueNames[p] = strings.Join(h[len(h)-depth-1:], "") - break - } - if depth == len(h)-1 { - uniqueNames[p] = strings.Join(h, "") - } - } - } +// Take the names of every proto message and generate a unique reference for each, according to the given strategy. +func resolveFullyQualifiedNameToOpenAPINames(messages []string, namingStrategy string) map[string]string { + strategyFn := LookupNamingStrategy(namingStrategy) + if strategyFn == nil { + return nil } - return uniqueNames + return strategyFn(messages) } -var canRegexp = regexp.MustCompile("{([a-zA-Z][a-zA-Z0-9_.]*).*}") +var canRegexp = regexp.MustCompile("{([a-zA-Z][a-zA-Z0-9_.]*)([^}]*)}") -// OpenAPI expects paths of the form /path/{string_value} but grpc-gateway paths are expected to be of the form /path/{string_value=strprefix/*}. This should reformat it correctly. -func templateToOpenAPIPath(path string, reg *descriptor.Registry, fields []*descriptor.Field, msgs []*descriptor.Message) string { +// templateToParts will split a URL template as defined by https://github.com/googleapis/googleapis/blob/master/google/api/http.proto +// into a string slice with each part as an element of the slice for use by `partsToOpenAPIPath` and `partsToRegexpMap`. +func templateToParts(path string, reg *descriptor.Registry, fields []*descriptor.Field, msgs []*descriptor.Message) []string { // It seems like the right thing to do here is to just use // strings.Split(path, "/") but that breaks badly when you hit a url like // /{my_field=prefix/*}/ and end up with 2 sections representing my_field. @@ -758,28 +922,86 @@ func templateToOpenAPIPath(path string, reg *descriptor.Registry, fields []*desc // Now append the last element to parts parts = append(parts, buffer) - // Parts is now an array of segments of the path. Interestingly, since the - // syntax for this subsection CAN be handled by a regexp since it has no - // memory. + return parts +} + +// partsToOpenAPIPath converts each path part of the form /path/{string_value=strprefix/*} which is defined in +// https://github.com/googleapis/googleapis/blob/master/google/api/http.proto to the OpenAPI expected form /path/{string_value}. +// For example this would replace the path segment of "{foo=bar/*}" with "{foo}" or "prefix{bang=bash/**}" with "prefix{bang}". +// OpenAPI 2 only allows simple path parameters with the constraints on that parameter specified in the OpenAPI +// schema's "pattern" instead of in the path parameter itself. +func partsToOpenAPIPath(parts []string) string { for index, part := range parts { - // If part is a resource name such as "parent", "name", "user.name", the format info must be retained. - prefix := canRegexp.ReplaceAllString(part, "$1") - if isResourceName(prefix) { - continue - } parts[index] = canRegexp.ReplaceAllString(part, "{$1}") } - return strings.Join(parts, "/") } -func isResourceName(prefix string) bool { - words := strings.Split(prefix, ".") - l := len(words) - field := words[l-1] - words = strings.Split(field, ":") - field = words[0] - return field == "parent" || field == "name" +// partsToRegexpMap returns a map of parameter name to ECMA 262 patterns +// which is what the "pattern" field on an OpenAPI parameter expects. +// See https://swagger.io/specification/v2/ (Parameter Object) and +// https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3. +// The expression is generated based on expressions defined by https://github.com/googleapis/googleapis/blob/master/google/api/http.proto +// "Path Template Syntax" section which allow for a "param_name=foobar/*/bang/**" style expressions inside +// the path parameter placeholders that indicate constraints on the values of those parameters. +// This function will scan the split parts of a path template for parameters and +// outputs a map of the name of the parameter to a ECMA regular expression. See the http.proto file for descriptions +// of the supported syntax. This function will ignore any path parameters that don't contain a "=" after the +// parameter name. For supported parameters, we assume "*" represent all characters except "/" as it's +// intended to match a single path element and we assume "**" matches any character as it's intended to match multiple +// path elements. +// For example "{name=organizations/*/roles/*}" would produce the regular expression for the "name" parameter of +// "organizations/[^/]+/roles/[^/]+" or "{bar=bing/*/bang/**}" would produce the regular expression for the "bar" +// parameter of "bing/[^/]+/bang/.+". +func partsToRegexpMap(parts []string) map[string]string { + regExps := make(map[string]string) + for _, part := range parts { + if submatch := canRegexp.FindStringSubmatch(part); len(submatch) > 2 { + if strings.HasPrefix(submatch[2], "=") { // this part matches the standard and should be made into a regular expression + // assume the string's characters other than "**" and "*" are literals (not necessarily a good assumption 100% of the times, but it will support most use cases) + regex := submatch[2][1:] + regex = strings.ReplaceAll(regex, "**", ".+") // ** implies any character including "/" + regex = strings.ReplaceAll(regex, "*", "[^/]+") // * implies any character except "/" + regExps[submatch[1]] = regex + } + } + } + return regExps +} + +func renderServiceTags(services []*descriptor.Service, reg *descriptor.Registry) []openapiTagObject { + var tags []openapiTagObject + for _, svc := range services { + if !isVisible(getServiceVisibilityOption(svc), reg) { + continue + } + tagName := svc.GetName() + if pkg := svc.File.GetPackage(); pkg != "" && reg.IsIncludePackageInTags() { + tagName = pkg + "." + tagName + } + + tag := openapiTagObject{ + Name: tagName, + } + if proto.HasExtension(svc.Options, openapi_options.E_Openapiv2Tag) { + ext := proto.GetExtension(svc.Options, openapi_options.E_Openapiv2Tag) + opts, ok := ext.(*openapi_options.Tag) + if !ok { + glog.Errorf("extension is %T; want an OpenAPI Tag object", ext) + return nil + } + + tag.Description = opts.Description + if opts.ExternalDocs != nil { + tag.ExternalDocs = &openapiExternalDocumentationObject{ + Description: opts.ExternalDocs.Description, + URL: opts.ExternalDocs.Url, + } + } + } + tags = append(tags, tag) + } + return tags } func renderServices(services []*descriptor.Service, paths openapiPathsObject, reg *descriptor.Registry, requestResponseRefs, customRefs refMap, msgs []*descriptor.Message) error { @@ -791,10 +1013,24 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re lastFile = svc.File svcBaseIdx = svcIdx } + + if !isVisible(getServiceVisibilityOption(svc), reg) { + continue + } + for methIdx, meth := range svc.Methods { + if !isVisible(getMethodVisibilityOption(meth), reg) { + continue + } + for bIdx, b := range meth.Bindings { + operationFunc := operationForMethod(b.HTTPMethod) // Iterate over all the OpenAPI parameters parameters := openapiParametersObject{} + // split the path template into its parts + parts := templateToParts(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs) + // extract any constraints specified in the path placeholders into ECMA regular expressions + pathParamRegexpMap := partsToRegexpMap(parts) for _, parameter := range b.PathParams { var paramType, paramFormat, desc, collectionFormat, defaultValue string @@ -822,11 +1058,11 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re } paramType = "string" paramFormat = "" - enumNames = listEnumNames(enum) + enumNames = listEnumNames(reg, enum) if reg.GetEnumsAsInts() { paramType = "integer" paramFormat = "" - enumNames = listEnumNumbers(enum) + enumNames = listEnumNumbers(reg, enum) } schema := schemaOfField(parameter.Target, reg, customRefs) desc = schema.Description @@ -865,6 +1101,10 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re if reg.GetUseJSONNamesForFields() { parameterString = lowerCamelCase(parameterString, meth.RequestType.Fields, msgs) } + var pattern string + if regExp, ok := pathParamRegexpMap[parameterString]; ok { + pattern = regExp + } parameters = append(parameters, openapiParameterObject{ Name: parameterString, Description: desc, @@ -878,39 +1118,70 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re Items: items, CollectionFormat: collectionFormat, MinItems: minItems, + Pattern: pattern, }) } // Now check if there is a body parameter if b.Body != nil { + // Recursively render fields as definitions as long as they contain path parameters. + // Special case for top level body if we don't have a body field. var schema openapiSchemaObject desc := "" - + var bodyFieldName string + schema = openapiSchemaObject{ + schemaCore: schemaCore{}, + } if len(b.Body.FieldPath) == 0 { - schema = openapiSchemaObject{ - schemaCore: schemaCore{}, - } - + // No field for body, use type. + bodyFieldName = "body" wknSchemaCore, isWkn := wktSchemas[meth.RequestType.FQMN()] - if !isWkn { - err := schema.setRefFromFQN(meth.RequestType.FQMN(), reg) - if err != nil { - return err - } - } else { + if isWkn { schema.schemaCore = wknSchemaCore - // Special workaround for Empty: it's well-known type but wknSchemas only returns schema.schemaCore; but we need to set schema.Properties which is a level higher. if meth.RequestType.FQMN() == ".google.protobuf.Empty" { schema.Properties = &openapiSchemaObjectProperties{} } + } else { + if len(b.PathParams) == 0 { + err := schema.setRefFromFQN(meth.RequestType.FQMN(), reg) + if err != nil { + return err + } + } else { + var err error + schema, err = renderMessageAsDefinition(meth.RequestType, reg, customRefs, b.PathParams) + if err != nil { + return err + } + if schema.Properties == nil || len(*schema.Properties) == 0 { + glog.Warningf("created a body with 0 properties in the message, this might be unintended: %s", *meth.RequestType) + } + } } } else { - lastField := b.Body.FieldPath[len(b.Body.FieldPath)-1] - schema = schemaOfField(lastField.Target, reg, customRefs) - if schema.Description != "" { - desc = schema.Description + // Body field path is limited to one path component. From google.api.HttpRule.body: + // "NOTE: the referred field must be present at the top-level of the request message type." + // Ref: https://github.com/googleapis/googleapis/blob/b3397f5febbf21dfc69b875ddabaf76bee765058/google/api/http.proto#L350-L352 + if len(b.Body.FieldPath) > 1 { + return fmt.Errorf("Body of request '%s' is not a top level field: '%v'.", meth.Service.GetName(), b.Body.FieldPath) + } + bodyField := b.Body.FieldPath[0] + if reg.GetUseJSONNamesForFields() { + bodyFieldName = lowerCamelCase(bodyField.Name, meth.RequestType.Fields, msgs) + } else { + bodyFieldName = bodyField.Name + } + // Align pathParams with body field path. + pathParams := subPathParams(bodyFieldName, b.PathParams) + var err error + schema, err = renderFieldAsDefinition(bodyField.Target, reg, customRefs, pathParams) + if err != nil { + return err + } + if schema.Title != "" { + desc = mergeDescription(schema) } else { - desc = fieldProtoComments(reg, lastField.Target.Message, lastField.Target) + desc = fieldProtoComments(reg, bodyField.Target.Message, bodyField.Target) } } @@ -918,30 +1189,67 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re desc += " (streaming inputs)" } parameters = append(parameters, openapiParameterObject{ - Name: "body", + Name: bodyFieldName, Description: desc, In: "body", Required: true, Schema: &schema, }) - // add the parameters to the query string - queryParams, err := messageToQueryParameters(meth.RequestType, reg, b.PathParams, b.Body) - if err != nil { - return err - } - parameters = append(parameters, queryParams...) - } else if b.HTTPMethod == "GET" || b.HTTPMethod == "DELETE" { - // add the parameters to the query string - queryParams, err := messageToQueryParameters(meth.RequestType, reg, b.PathParams, b.Body) - if err != nil { - return err - } - parameters = append(parameters, queryParams...) } - pathItemObject, ok := paths[templateToOpenAPIPath(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs)] + // add the parameters to the query string + queryParams, err := messageToQueryParameters(meth.RequestType, reg, b.PathParams, b.Body) + if err != nil { + return err + } + parameters = append(parameters, queryParams...) + + path := partsToOpenAPIPath(parts) + pathItemObject, ok := paths[path] if !ok { pathItemObject = openapiPathItemObject{} + } else { + // handle case where we have an existing mapping for the same path and method + existingOperationObject := operationFunc(&pathItemObject) + if existingOperationObject != nil { + var firstPathParameter *openapiParameterObject + var firstParamIndex int + for index, param := range parameters { + if param.In == "path" { + firstPathParameter = ¶m + firstParamIndex = index + break + } + } + if firstPathParameter == nil { + // Without a path parameter, there is nothing to vary to support multiple mappings of the same path/method. + // Previously this did not log an error and only overwrote the mapping, we now log the error but + // still overwrite the mapping + glog.Errorf("Duplicate mapping for path %s %s", b.HTTPMethod, path) + } else { + newPathCount := 0 + var newPath string + var newPathElement string + // Iterate until there is not an existing operation that matches the same escaped path. + // Most of the time this will only be a single iteration, but a large API could technically have + // a pretty large amount of these if it used similar patterns for all its functions. + for existingOperationObject != nil { + newPathCount += 1 + newPathElement = firstPathParameter.Name + pathParamUniqueSuffixDeliminator + strconv.Itoa(newPathCount) + newPath = strings.ReplaceAll(path, "{"+firstPathParameter.Name+"}", "{"+newPathElement+"}") + if newPathItemObject, ok := paths[newPath]; ok { + existingOperationObject = operationFunc(&newPathItemObject) + } else { + existingOperationObject = nil + } + } + // update the pathItemObject we are adding to with the new path + pathItemObject = paths[newPath] + firstPathParameter.Name = newPathElement + path = newPath + parameters[firstParamIndex] = *firstPathParameter + } + } } methProtoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.ServiceDescriptorProto)(nil)), "Method") @@ -1023,6 +1331,7 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re "200": openapiResponseObject{ Description: desc, Schema: responseSchema, + Headers: openapiHeadersObject{}, }, }, } @@ -1119,6 +1428,13 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re if resp.Examples != nil { respObj.Examples = openapiExamplesFromProtoExamples(resp.Examples) } + if resp.Headers != nil { + hdrs, err := processHeaders(resp.Headers) + if err != nil { + return err + } + respObj.Headers = hdrs + } if resp.Extensions != nil { exts, err := processExtensions(resp.Extensions) if err != nil { @@ -1158,7 +1474,7 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re case "PATCH": pathItemObject.Patch = operationObject } - paths[templateToOpenAPIPath(b.PathTmpl.Template, reg, meth.RequestType.Fields, msgs)] = pathItemObject + paths[path] = pathItemObject } } } @@ -1167,6 +1483,31 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re return nil } +func mergeDescription(schema openapiSchemaObject) string { + desc := schema.Description + if schema.Title != "" { // join title because title of parameter object will be ignored + desc = strings.TrimSpace(schema.Title + paragraphDeliminator + schema.Description) + } + return desc +} + +func operationForMethod(httpMethod string) func(*openapiPathItemObject) *openapiOperationObject { + switch httpMethod { + case "GET": + return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Get } + case "POST": + return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Post } + case "PUT": + return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Put } + case "DELETE": + return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Delete } + case "PATCH": + return func(obj *openapiPathItemObject) *openapiOperationObject { return obj.Patch } + default: + return nil + } +} + // This function is called with a param which contains the entire definition of a method. func applyTemplate(p param) (*openapiSwaggerObject, error) { // Create the basic template object. This is the object that everything is @@ -1191,6 +1532,7 @@ func applyTemplate(p param) (*openapiSwaggerObject, error) { if err := renderServices(p.Services, s.Paths, p.reg, requestResponseRefs, customRefs, p.Messages); err != nil { panic(err) } + s.Tags = append(s.Tags, renderServiceTags(p.Services, p.reg)...) messages := messageMap{} streamingMessages := messageMap{} @@ -1210,20 +1552,22 @@ func applyTemplate(p param) (*openapiSwaggerObject, error) { // Find all the service's messages and enumerations that are defined (recursively) // and write request, response and other custom (but referenced) types out as definition objects. findServicesMessagesAndEnumerations(p.Services, p.reg, messages, streamingMessages, enums, requestResponseRefs) - renderMessagesAsDefinition(messages, s.Definitions, p.reg, customRefs) + if err := renderMessagesAsDefinition(messages, s.Definitions, p.reg, customRefs, nil); err != nil { + return nil, err + } renderEnumerationsAsDefinition(enums, s.Definitions, p.reg) // File itself might have some comments and metadata. packageProtoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.FileDescriptorProto)(nil)), "Package") packageComments := protoComments(p.reg, p.File, nil, "Package", packageProtoPath) if err := updateOpenAPIDataFromComments(p.reg, &s, p, packageComments, true); err != nil { - panic(err) + return nil, err } // There may be additional options in the OpenAPI option in the proto. spb, err := getFileOpenAPIOption(p.reg, p.File) if err != nil { - panic(err) + return nil, err } if spb != nil { if spb.Swagger != "" { @@ -1374,6 +1718,9 @@ func applyTemplate(p param) (*openapiSwaggerObject, error) { for _, secReq := range spb.Security { newSecReq := openapiSecurityRequirementObject{} for secReqKey, secReqValue := range secReq.SecurityRequirement { + if secReqValue == nil { + return nil, fmt.Errorf("malformed security requirement spec for key %q; value is required", secReqKey) + } newSecReqValue := make([]string, len(secReqValue.Scope)) copy(newSecReqValue, secReqValue.Scope) newSecReq[secReqKey] = newSecReqValue @@ -1434,7 +1781,9 @@ func applyTemplate(p param) (*openapiSwaggerObject, error) { // Finally add any references added by users that aren't // otherwise rendered. - addCustomRefs(s.Definitions, p.reg, customRefs) + if err := addCustomRefs(s.Definitions, p.reg, customRefs); err != nil { + return nil, err + } return &s, nil } @@ -1455,6 +1804,180 @@ func processExtensions(inputExts map[string]*structpb.Value) ([]extension, error return exts, nil } +func validateHeaderTypeAndFormat(headerType string, format string) error { + // The type of the object. The value MUST be one of "string", "number", "integer", "boolean", or "array" + // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject + // Note: currently not implementing array as we are only implementing this in the operation response context + switch headerType { + // the format property is an open string-valued property, and can have any value to support documentation needs + // primary check for format is to ensure that the number/integer formats are extensions of the specified type + // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#dataTypeFormat + case "string": + return nil + case "number": + switch format { + case "uint", + "uint8", + "uint16", + "uint32", + "uint64", + "int", + "int8", + "int16", + "int32", + "int64", + "float", + "float32", + "float64", + "complex64", + "complex128", + "double", + "byte", + "rune", + "uintptr", + "": + return nil + default: + return fmt.Errorf("the provided format %q is not a valid extension of the type %q", format, headerType) + } + case "integer": + switch format { + case "uint", + "uint8", + "uint16", + "uint32", + "uint64", + "int", + "int8", + "int16", + "int32", + "int64", + "": + return nil + default: + return fmt.Errorf("the provided format %q is not a valid extension of the type %q", format, headerType) + } + case "boolean": + return nil + } + return fmt.Errorf("the provided header type %q is not supported", headerType) +} + +func validateDefaultValueTypeAndFormat(headerType string, defaultValue string, format string) error { + switch headerType { + case "string": + if !isQuotedString(defaultValue) { + return fmt.Errorf("the provided default value %q does not match provider type %q, or is not properly quoted with escaped quotations", defaultValue, headerType) + } + switch format { + case "date-time": + unquoteTime := strings.Trim(defaultValue, `"`) + _, err := time.Parse(time.RFC3339, unquoteTime) + if err != nil { + return fmt.Errorf("the provided default value %q is not a valid RFC3339 date-time string", defaultValue) + } + case "date": + const ( + layoutRFC3339Date = "2006-01-02" + ) + unquoteDate := strings.Trim(defaultValue, `"`) + _, err := time.Parse(layoutRFC3339Date, unquoteDate) + if err != nil { + return fmt.Errorf("the provided default value %q is not a valid RFC3339 date-time string", defaultValue) + } + } + case "number": + err := isJSONNumber(defaultValue, headerType) + if err != nil { + return err + } + case "integer": + switch format { + case "int32": + _, err := strconv.ParseInt(defaultValue, 0, 32) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format) + } + case "uint32": + _, err := strconv.ParseUint(defaultValue, 0, 32) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format) + } + case "int64": + _, err := strconv.ParseInt(defaultValue, 0, 64) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format) + } + case "uint64": + _, err := strconv.ParseUint(defaultValue, 0, 64) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provided format %q", defaultValue, format) + } + default: + _, err := strconv.ParseInt(defaultValue, 0, 64) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provided type %q", defaultValue, headerType) + } + } + case "boolean": + if !isBool(defaultValue) { + return fmt.Errorf("the provided default value %q does not match provider type %q", defaultValue, headerType) + } + } + return nil +} + +func isQuotedString(s string) bool { + return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' +} + +func isJSONNumber(s string, t string) error { + val, err := strconv.ParseFloat(s, 64) + if err != nil { + return fmt.Errorf("the provided default value %q does not match provider type %q", s, t) + } + // Floating point values that cannot be represented as sequences of digits (such as Infinity and NaN) are not permitted. + // See: https://tools.ietf.org/html/rfc4627#section-2.4 + if math.IsInf(val, 0) || math.IsNaN(val) { + return fmt.Errorf("the provided number %q is not a valid JSON number", s) + } + + return nil +} + +func isBool(s string) bool { + // Unable to use strconv.ParseBool because it returns truthy values https://golang.org/pkg/strconv/#example_ParseBool + // per https://swagger.io/specification/v2/#data-types + // type: boolean represents two values: true and false. Note that truthy and falsy values such as "true", "", 0 or null are not considered boolean values. + return s == "true" || s == "false" +} + +func processHeaders(inputHdrs map[string]*openapi_options.Header) (openapiHeadersObject, error) { + hdrs := map[string]openapiHeaderObject{} + for k, v := range inputHdrs { + header := textproto.CanonicalMIMEHeaderKey(k) + ret := openapiHeaderObject{ + Description: v.Description, + Format: v.Format, + Pattern: v.Pattern, + } + err := validateHeaderTypeAndFormat(v.Type, v.Format) + if err != nil { + return nil, err + } + ret.Type = v.Type + if v.Default != "" { + err := validateDefaultValueTypeAndFormat(v.Type, v.Default, v.Format) + if err != nil { + return nil, err + } + ret.Default = RawExample(v.Default) + } + hdrs[header] = ret + } + return hdrs, nil +} + // updateOpenAPIDataFromComments updates a OpenAPI object based on a comment // from the proto file. // @@ -1501,13 +2024,13 @@ func updateOpenAPIDataFromComments(reg *descriptor.Registry, swaggerObject inter usingTitle = true } - paragraphs := strings.Split(comment, "\n\n") + paragraphs := strings.Split(comment, paragraphDeliminator) // If there is a summary (or summary-equivalent) and it's empty, use the first // paragraph as summary, and the rest as description. if summaryValue.CanSet() { summary := strings.TrimSpace(paragraphs[0]) - description := strings.TrimSpace(strings.Join(paragraphs[1:], "\n\n")) + description := strings.TrimSpace(strings.Join(paragraphs[1:], paragraphDeliminator)) if !usingTitle || (len(summary) > 0 && summary[len(summary)-1] != '.') { // overrides the schema value only if it's empty // keep the comment precedence when updating the package definition @@ -1532,7 +2055,7 @@ func updateOpenAPIDataFromComments(reg *descriptor.Registry, swaggerObject inter // whole comment into description if the OpenAPI object description is empty. if descriptionValue.CanSet() { if descriptionValue.Len() == 0 || isPackageObject { - descriptionValue.Set(reflect.ValueOf(strings.Join(paragraphs, "\n\n"))) + descriptionValue.Set(reflect.ValueOf(strings.Join(paragraphs, paragraphDeliminator))) } return nil } @@ -1554,6 +2077,9 @@ func enumValueProtoComments(reg *descriptor.Registry, enum *descriptor.Enum) str protoPath := protoPathIndex(reflect.TypeOf((*descriptorpb.EnumDescriptorProto)(nil)), "Value") var comments []string for idx, value := range enum.GetValue() { + if !isVisible(getEnumValueVisibilityOption(value), reg) { + continue + } name := value.GetName() if reg.GetEnumsAsInts() { name = strconv.Itoa(int(value.GetNumber())) @@ -1810,6 +2336,81 @@ func extractJSONSchemaFromFieldDescriptor(fd *descriptorpb.FieldDescriptorProto) return opts, nil } +func extractFieldBehaviorFromFieldDescriptor(fd *descriptorpb.FieldDescriptorProto) ([]annotations.FieldBehavior, error) { + if fd.Options == nil { + return nil, nil + } + if !proto.HasExtension(fd.Options, annotations.E_FieldBehavior) { + return nil, nil + } + ext := proto.GetExtension(fd.Options, annotations.E_FieldBehavior) + opts, ok := ext.([]annotations.FieldBehavior) + if !ok { + return nil, fmt.Errorf("extension is %T; want a []FieldBehavior object", ext) + } + return opts, nil +} + +func getFieldVisibilityOption(fd *descriptor.Field) *visibility.VisibilityRule { + if fd.Options == nil { + return nil + } + if !proto.HasExtension(fd.Options, visibility.E_FieldVisibility) { + return nil + } + ext := proto.GetExtension(fd.Options, visibility.E_FieldVisibility) + opts, ok := ext.(*visibility.VisibilityRule) + if !ok { + return nil + } + return opts +} + +func getServiceVisibilityOption(fd *descriptor.Service) *visibility.VisibilityRule { + if fd.Options == nil { + return nil + } + if !proto.HasExtension(fd.Options, visibility.E_ApiVisibility) { + return nil + } + ext := proto.GetExtension(fd.Options, visibility.E_ApiVisibility) + opts, ok := ext.(*visibility.VisibilityRule) + if !ok { + return nil + } + return opts +} + +func getMethodVisibilityOption(fd *descriptor.Method) *visibility.VisibilityRule { + if fd.Options == nil { + return nil + } + if !proto.HasExtension(fd.Options, visibility.E_MethodVisibility) { + return nil + } + ext := proto.GetExtension(fd.Options, visibility.E_MethodVisibility) + opts, ok := ext.(*visibility.VisibilityRule) + if !ok { + return nil + } + return opts +} + +func getEnumValueVisibilityOption(fd *descriptorpb.EnumValueDescriptorProto) *visibility.VisibilityRule { + if fd.Options == nil { + return nil + } + if !proto.HasExtension(fd.Options, visibility.E_ValueVisibility) { + return nil + } + ext := proto.GetExtension(fd.Options, visibility.E_ValueVisibility) + opts, ok := ext.(*visibility.VisibilityRule) + if !ok { + return nil + } + return opts +} + func getMethodOpenAPIOption(reg *descriptor.Registry, meth *descriptor.Method) (*openapi_options.Operation, error) { opts, err := extractOperationOptionFromMethodDescriptor(meth.MethodDescriptorProto) if err != nil { @@ -1870,6 +2471,17 @@ func getFieldOpenAPIOption(reg *descriptor.Registry, fd *descriptor.Field) (*ope return opts, nil } +func getFieldBehaviorOption(reg *descriptor.Registry, fd *descriptor.Field) ([]annotations.FieldBehavior, error) { + opts, err := extractFieldBehaviorFromFieldDescriptor(fd.FieldDescriptorProto) + if err != nil { + return nil, err + } + if opts != nil { + return opts, nil + } + return opts, nil +} + func protoJSONSchemaToOpenAPISchemaCore(j *openapi_options.JSONSchema, reg *descriptor.Registry, refs refMap) schemaCore { ret := schemaCore{} @@ -1916,9 +2528,48 @@ func updateswaggerObjectFromJSONSchema(s *openapiSchemaObject, j *openapi_option s.MaxProperties = j.GetMaxProperties() s.MinProperties = j.GetMinProperties() s.Required = j.GetRequired() + if reg.GetUseJSONNamesForFields() { + for i, r := range s.Required { + // TODO(oyvindwe): Look up field and use field.GetJsonName()? + s.Required[i] = doCamelCase(r) + } + } + s.Enum = j.GetEnum() if overrideType := j.GetType(); len(overrideType) > 0 { s.Type = strings.ToLower(overrideType[0].String()) } + if j != nil && j.GetExample() != "" { + s.Example = RawExample(j.GetExample()) + } + if j != nil && j.GetFormat() != "" { + s.Format = j.GetFormat() + } +} + +func updateSwaggerObjectFromFieldBehavior(s *openapiSchemaObject, j []annotations.FieldBehavior, reg *descriptor.Registry, field *descriptor.Field) { + // Per the JSON Reference syntax: Any members other than "$ref" in a JSON Reference object SHALL be ignored. + // https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03#section-3 + if s.Ref != "" { + return + } + + for _, fb := range j { + switch fb { + case annotations.FieldBehavior_REQUIRED: + if reg.GetUseJSONNamesForFields() { + s.Required = append(s.Required, *field.JsonName) + } else { + s.Required = append(s.Required, *field.Name) + } + case annotations.FieldBehavior_OUTPUT_ONLY: + s.ReadOnly = true + case annotations.FieldBehavior_FIELD_BEHAVIOR_UNSPECIFIED: + case annotations.FieldBehavior_OPTIONAL: + case annotations.FieldBehavior_INPUT_ONLY: + // OpenAPI v3 supports a writeOnly property, but this is not supported in Open API v2 + case annotations.FieldBehavior_IMMUTABLE: + } + } } func openapiSchemaFromProtoSchema(s *openapi_options.Schema, reg *descriptor.Registry, refs refMap, data interface{}) openapiSchemaObject { @@ -1930,7 +2581,7 @@ func openapiSchemaFromProtoSchema(s *openapi_options.Schema, reg *descriptor.Reg updateswaggerObjectFromJSONSchema(&ret, s.GetJsonSchema(), reg, data) if s != nil && s.Example != "" { - ret.Example = json.RawMessage(s.Example) + ret.Example = RawExample(s.Example) } return ret @@ -2005,9 +2656,9 @@ func protoExternalDocumentationToOpenAPIExternalDocumentation(in *openapi_option } } -func addCustomRefs(d openapiDefinitionsObject, reg *descriptor.Registry, refs refMap) { +func addCustomRefs(d openapiDefinitionsObject, reg *descriptor.Registry, refs refMap) error { if len(refs) == 0 { - return + return nil } msgMap := make(messageMap) enumMap := make(enumMap) @@ -2035,11 +2686,13 @@ func addCustomRefs(d openapiDefinitionsObject, reg *descriptor.Registry, refs re // ?? Should be either enum or msg } - renderMessagesAsDefinition(msgMap, d, reg, refs) + if err := renderMessagesAsDefinition(msgMap, d, reg, refs, nil); err != nil { + return err + } renderEnumerationsAsDefinition(enumMap, d, reg) // Run again in case any new refs were added - addCustomRefs(d, reg, refs) + return addCustomRefs(d, reg, refs) } func lowerCamelCase(fieldName string, fields []*descriptor.Field, msgs []*descriptor.Message) string { @@ -2093,3 +2746,30 @@ func getReservedJSONName(fieldName string, messageNameToFieldsToJSONName map[str fieldNames := strings.Split(fieldName, ".") return getReservedJSONName(strings.Join(fieldNames[1:], "."), messageNameToFieldsToJSONName, fieldNameToType) } + +func find(a []string, x string) int { + // This is a linear search but we are dealing with a small number of fields + for i, n := range a { + if x == n { + return i + } + } + return -1 +} + +// Make a deep copy of the outer parameters that has paramName as the first component, +// but remove the first component of the field path. +func subPathParams(paramName string, outerParams []descriptor.Parameter) []descriptor.Parameter { + var innerParams []descriptor.Parameter + for _, p := range outerParams { + if len(p.FieldPath) > 1 && p.FieldPath[0].Name == paramName { + subParam := descriptor.Parameter{ + FieldPath: p.FieldPath[1:], + Target: p.Target, + Method: p.Method, + } + innerParams = append(innerParams, subParam) + } + } + return innerParams +} diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go deleted file mode 100644 index 2b55842..0000000 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/template_test.go +++ /dev/null @@ -1,3702 +0,0 @@ -package genopenapi - -import ( - "encoding/json" - "errors" - "fmt" - "reflect" - "strings" - "testing" - - "github.com/google/go-cmp/cmp" - // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" - // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor/openapiconfig" - "github.com/binchencoder/ease-gateway/gateway/internal/descriptor/openapiconfig" - "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" - // openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" - openapi_options "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options" - // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/binchencoder/ease-gateway/gateway/runtime" - "google.golang.org/genproto/protobuf/field_mask" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protodesc" - "google.golang.org/protobuf/types/descriptorpb" - "google.golang.org/protobuf/types/known/durationpb" - "google.golang.org/protobuf/types/known/structpb" - "google.golang.org/protobuf/types/known/timestamppb" - "google.golang.org/protobuf/types/known/wrapperspb" - "google.golang.org/protobuf/types/pluginpb" -) - -var marshaler = &runtime.JSONPb{} - -func crossLinkFixture(f *descriptor.File) *descriptor.File { - for _, m := range f.Messages { - m.File = f - } - for _, svc := range f.Services { - svc.File = f - for _, m := range svc.Methods { - m.Service = svc - for _, b := range m.Bindings { - b.Method = m - for _, param := range b.PathParams { - param.Method = m - } - } - } - } - return f -} - -func reqFromFile(f *descriptor.File) *pluginpb.CodeGeneratorRequest { - return &pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{ - f.FileDescriptorProto, - }, - FileToGenerate: []string{f.GetName()}, - } -} - -func TestMessageToQueryParametersWithEnumAsInt(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - Message string - Params []openapiParameterObject - } - - tests := []test{ - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("b"), - Type: descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(), - Number: proto.Int32(2), - }, - { - Name: proto.String("c"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Number: proto.Int32(3), - }, - }, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "a", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "b", - In: "query", - Required: false, - Type: "number", - Format: "double", - }, - { - Name: "c", - In: "query", - Required: false, - Type: "array", - CollectionFormat: "multi", - }, - }, - }, - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Nested"), - Number: proto.Int32(1), - }, - }, - }, - { - Name: proto.String("Nested"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("deep"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Nested.DeepNested"), - Number: proto.Int32(2), - }, - }, - NestedType: []*descriptorpb.DescriptorProto{{ - Name: proto.String("DeepNested"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("b"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("c"), - Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(), - TypeName: proto.String(".example.Nested.DeepNested.DeepEnum"), - Number: proto.Int32(2), - }, - }, - EnumType: []*descriptorpb.EnumDescriptorProto{ - { - Name: proto.String("DeepEnum"), - Value: []*descriptorpb.EnumValueDescriptorProto{ - {Name: proto.String("FALSE"), Number: proto.Int32(0)}, - {Name: proto.String("TRUE"), Number: proto.Int32(1)}, - }, - }, - }, - }}, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "nested.a", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "nested.deep.b", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "nested.deep.c", - In: "query", - Required: false, - Type: "integer", - Enum: []string{"0", "1"}, - Default: "0", - }, - }, - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - reg.SetEnumsAsInts(true) - msgs := []*descriptor.Message{} - for _, msgdesc := range test.MsgDescs { - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err != nil { - t.Fatalf("failed to convert message to query parameters: %s", err) - } - // avoid checking Items for array types - for i := range params { - params[i].Items = nil - } - if !reflect.DeepEqual(params, test.Params) { - t.Errorf("expected %v, got %v", test.Params, params) - } - } -} - -func TestMessageToQueryParameters(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - Message string - Params []openapiParameterObject - } - - tests := []test{ - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("b"), - Type: descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(), - Number: proto.Int32(2), - }, - { - Name: proto.String("c"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Number: proto.Int32(3), - }, - }, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "a", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "b", - In: "query", - Required: false, - Type: "number", - Format: "double", - }, - { - Name: "c", - In: "query", - Required: false, - Type: "array", - CollectionFormat: "multi", - }, - }, - }, - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Nested"), - Number: proto.Int32(1), - }, - }, - }, - { - Name: proto.String("Nested"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("deep"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Nested.DeepNested"), - Number: proto.Int32(2), - }, - }, - NestedType: []*descriptorpb.DescriptorProto{{ - Name: proto.String("DeepNested"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("b"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("c"), - Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(), - TypeName: proto.String(".example.Nested.DeepNested.DeepEnum"), - Number: proto.Int32(2), - }, - }, - EnumType: []*descriptorpb.EnumDescriptorProto{ - { - Name: proto.String("DeepEnum"), - Value: []*descriptorpb.EnumValueDescriptorProto{ - {Name: proto.String("FALSE"), Number: proto.Int32(0)}, - {Name: proto.String("TRUE"), Number: proto.Int32(1)}, - }, - }, - }, - }}, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "nested.a", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "nested.deep.b", - In: "query", - Required: false, - Type: "string", - }, - { - Name: "nested.deep.c", - In: "query", - Required: false, - Type: "string", - Enum: []string{"FALSE", "TRUE"}, - Default: "FALSE", - }, - }, - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - msgs := []*descriptor.Message{} - for _, msgdesc := range test.MsgDescs { - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err != nil { - t.Fatalf("failed to convert message to query parameters: %s", err) - } - // avoid checking Items for array types - for i := range params { - params[i].Items = nil - } - if !reflect.DeepEqual(params, test.Params) { - t.Errorf("expected %v, got %v", test.Params, params) - } - } -} - -// TestMessagetoQueryParametersNoRecursive, is a check that cyclical references between messages -// are not falsely detected given previous known edge-cases. -func TestMessageToQueryParametersNoRecursive(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - Message string - } - - tests := []test{ - // First test: - // Here is a message that has two of another message adjacent to one another in a nested message. - // There is no loop but this was previouly falsely flagged as a cycle. - // Example proto: - // message NonRecursiveMessage { - // string field = 1; - // } - // message BaseMessage { - // NonRecursiveMessage first = 1; - // NonRecursiveMessage second = 2; - // } - // message QueryMessage { - // BaseMessage first = 1; - // string second = 2; - // } - { - MsgDescs: []*descriptorpb.DescriptorProto{ - &descriptorpb.DescriptorProto{ - Name: proto.String("QueryMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("first"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.BaseMessage"), - Number: proto.Int32(1), - }, - { - Name: proto.String("second"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(2), - }, - }, - }, - &descriptorpb.DescriptorProto{ - Name: proto.String("BaseMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("first"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.NonRecursiveMessage"), - Number: proto.Int32(1), - }, - { - Name: proto.String("second"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.NonRecursiveMessage"), - Number: proto.Int32(2), - }, - }, - }, - // Note there is no recursive nature to this message - &descriptorpb.DescriptorProto{ - Name: proto.String("NonRecursiveMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("field"), - //Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - }, - }, - }, - Message: "QueryMessage", - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - msgs := []*descriptor.Message{} - for _, msgdesc := range test.MsgDescs { - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - - _, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err != nil { - t.Fatalf("No recursion error should be thrown: %s", err) - } - } -} - -// TestMessagetoQueryParametersRecursive, is a check that cyclical references between messages -// are handled gracefully. The goal is to insure that attempts to add messages with cyclical -// references to query-parameters returns an error message. -func TestMessageToQueryParametersRecursive(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - Message string - } - - tests := []test{ - // First test: - // Here we test that a message that references it self through a field will return an error. - // Example proto: - // message DirectRecursiveMessage { - // DirectRecursiveMessage nested = 1; - // } - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("DirectRecursiveMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.DirectRecursiveMessage"), - Number: proto.Int32(1), - }, - }, - }, - }, - Message: "DirectRecursiveMessage", - }, - // Second test: - // Here we test that a cycle through multiple messages is detected and that an error is returned. - // Sample: - // message Root { NodeMessage nested = 1; } - // message NodeMessage { CycleMessage nested = 1; } - // message CycleMessage { Root nested = 1; } - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("RootMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.NodeMessage"), - Number: proto.Int32(1), - }, - }, - }, - { - Name: proto.String("NodeMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.CycleMessage"), - Number: proto.Int32(1), - }, - }, - }, - { - Name: proto.String("CycleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.RootMessage"), - Number: proto.Int32(1), - }, - }, - }, - }, - Message: "RootMessage", - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - msgs := []*descriptor.Message{} - for _, msgdesc := range test.MsgDescs { - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - _, err = messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err == nil { - t.Fatalf("It should not be allowed to have recursive query parameters") - } - } -} - -func TestMessageToQueryParametersWithJsonName(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - Message string - Params []openapiParameterObject - } - - tests := []test{ - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("test_field_a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - JsonName: proto.String("testFieldA"), - }, - }, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "testFieldA", - In: "query", - Required: false, - Type: "string", - }, - }, - }, - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("SubMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("test_field_a"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - JsonName: proto.String("testFieldA"), - }, - }, - }, - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("sub_message"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.SubMessage"), - Number: proto.Int32(1), - JsonName: proto.String("subMessage"), - }, - }, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "subMessage.testFieldA", - In: "query", - Required: false, - Type: "string", - }, - }, - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(true) - msgs := []*descriptor.Message{} - for _, msgdesc := range test.MsgDescs { - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err != nil { - t.Fatalf("failed to convert message to query parameters: %s", err) - } - if !reflect.DeepEqual(params, test.Params) { - t.Errorf("expected %v, got %v", test.Params, params) - } - } -} - -func TestMessageToQueryParametersWellKnownTypes(t *testing.T) { - type test struct { - MsgDescs []*descriptorpb.DescriptorProto - WellKnownMsgDescs []*descriptorpb.DescriptorProto - Message string - Params []openapiParameterObject - } - - tests := []test{ - { - MsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("a_field_mask"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".google.protobuf.FieldMask"), - Number: proto.Int32(1), - }, - { - Name: proto.String("a_timestamp"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".google.protobuf.Timestamp"), - Number: proto.Int32(2), - }, - }, - }, - }, - WellKnownMsgDescs: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("FieldMask"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("paths"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Number: proto.Int32(1), - }, - }, - }, - { - Name: proto.String("Timestamp"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("seconds"), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("nanos"), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), - Number: proto.Int32(2), - }, - }, - }, - }, - Message: "ExampleMessage", - Params: []openapiParameterObject{ - { - Name: "a_field_mask", - In: "query", - Required: false, - Type: "array", - Items: &openapiItemsObject{ - Type: "string", - }, - CollectionFormat: "multi", - }, - { - Name: "a_timestamp", - In: "query", - Required: false, - Type: "string", - Format: "date-time", - }, - }, - }, - } - - for _, test := range tests { - reg := descriptor.NewRegistry() - reg.SetEnumsAsInts(true) - err := reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{ - { - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("google/well_known.proto"), - Package: proto.String("google.protobuf"), - Dependency: []string{}, - MessageType: test.WellKnownMsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - { - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("acme/example.proto"), - Package: proto.String("example"), - Dependency: []string{"google/well_known.proto"}, - MessageType: test.MsgDescs, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - }, - }) - if err != nil { - t.Fatalf("failed to load CodeGeneratorRequest: %v", err) - } - - message, err := reg.LookupMsg("", ".example."+test.Message) - if err != nil { - t.Fatalf("failed to lookup message: %s", err) - } - params, err := messageToQueryParameters(message, reg, []descriptor.Parameter{}, nil) - if err != nil { - t.Fatalf("failed to convert message to query parameters: %s", err) - } - if !reflect.DeepEqual(params, test.Params) { - t.Errorf("expected %v, got %v", test.Params, params) - } - } -} - -func TestApplyTemplateSimple(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew22): Figure out what this should really be - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - fileCL := crossLinkFixture(&file) - err := reg.Load(reqFromFile(fileCL)) - if err != nil { - t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) - return - } - result, err := applyTemplate(param{File: fileCL, reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := "", result.BasePath, "BasePath"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := ([]string)(nil), result.Schemes, "Schemes"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := []string{"application/json"}, result.Consumes, "Consumes"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := []string{"application/json"}, result.Produces, "Produces"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func TestApplyTemplateMultiService(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - } - - // Create two services that have the same method name. We will test that the - // operation IDs are different - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - svc2 := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("OtherService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", - }, - }, - }, - }, - }, - }, - { - ServiceDescriptorProto: svc2, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/ping", - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - fileCL := crossLinkFixture(&file) - err := reg.Load(reqFromFile(fileCL)) - if err != nil { - t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) - return - } - result, err := applyTemplate(param{File: fileCL, reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - - // Check that the two services have unique operation IDs even though they - // have the same method name. - if want, is := "ExampleService_Example", result.Paths["/v1/echo"].Get.OperationID; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", file, is, want) - } - if want, is := "OtherService_Example", result.Paths["/v1/ping"].Get.OperationID; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", file, is, want) - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func TestApplyTemplateOverrideOperationID(t *testing.T) { - newFile := func() *descriptor.File { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - Options: &descriptorpb.MethodOptions{}, - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - return &descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew22): Figure out what this should really be - }, - }, - }, - }, - }, - }, - }, - } - } - - verifyTemplateFromReq := func(t *testing.T, reg *descriptor.Registry, file *descriptor.File, opts *openapiconfig.OpenAPIOptions) { - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - fileCL := crossLinkFixture(file) - err := reg.Load(reqFromFile(fileCL)) - if err != nil { - t.Errorf("reg.Load(%#v) failed with %v; want success", *file, err) - return - } - if opts != nil { - if err := reg.RegisterOpenAPIOptions(opts); err != nil { - t.Fatalf("failed to register OpenAPI options: %s", err) - } - } - result, err := applyTemplate(param{File: fileCL, reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", *file, err) - return - } - if want, is := "MyExample", result.Paths["/v1/echo"].Get.OperationID; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).Paths[0].Get.OperationID = %s want to be %s", *file, is, want) - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", *file) - t.Errorf("got: %s", fmt.Sprint(result)) - } - } - - openapiOperation := openapi_options.Operation{ - OperationId: "MyExample", - } - - t.Run("verify override via method option", func(t *testing.T) { - file := newFile() - proto.SetExtension(proto.Message(file.Services[0].Methods[0].MethodDescriptorProto.Options), - openapi_options.E_Openapiv2Operation, &openapiOperation) - - reg := descriptor.NewRegistry() - verifyTemplateFromReq(t, reg, file, nil) - }) - - t.Run("verify override options annotations", func(t *testing.T) { - file := newFile() - reg := descriptor.NewRegistry() - opts := &openapiconfig.OpenAPIOptions{ - Method: []*openapiconfig.OpenAPIMethodOption{ - { - Method: "example.ExampleService.Example", - Option: &openapiOperation, - }, - }, - } - verifyTemplateFromReq(t, reg, file, opts) - }) -} - -func TestApplyTemplateExtensions(t *testing.T) { - newFile := func() *descriptor.File { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - Options: &descriptorpb.MethodOptions{}, - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - return &descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - Options: &descriptorpb.FileOptions{}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - Body: &descriptor.Body{FieldPath: nil}, - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew22): Figure out what this should really be - }, - }, - }, - }, - }, - }, - }, - } - } - swagger := openapi_options.Swagger{ - Info: &openapi_options.Info{ - Title: "test", - Extensions: map[string]*structpb.Value{ - "x-info-extension": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, - }, - }, - Extensions: map[string]*structpb.Value{ - "x-foo": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, - "x-bar": {Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{ - Values: []*structpb.Value{{Kind: &structpb.Value_StringValue{StringValue: "baz"}}}, - }}}, - }, - SecurityDefinitions: &openapi_options.SecurityDefinitions{ - Security: map[string]*openapi_options.SecurityScheme{ - "somescheme": { - Extensions: map[string]*structpb.Value{ - "x-security-baz": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, - }, - }, - }, - }, - } - openapiOperation := openapi_options.Operation{ - Responses: map[string]*openapi_options.Response{ - "200": { - Extensions: map[string]*structpb.Value{ - "x-resp-id": {Kind: &structpb.Value_StringValue{StringValue: "resp1000"}}, - }, - }, - }, - Extensions: map[string]*structpb.Value{ - "x-op-foo": {Kind: &structpb.Value_StringValue{StringValue: "baz"}}, - }, - } - verifyTemplateExtensions := func(t *testing.T, reg *descriptor.Registry, file *descriptor.File, - opts *openapiconfig.OpenAPIOptions) { - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - fileCL := crossLinkFixture(file) - err := reg.Load(reqFromFile(fileCL)) - if err != nil { - t.Errorf("reg.Load(%#v) failed with %v; want success", file, err) - return - } - if opts != nil { - if err := reg.RegisterOpenAPIOptions(opts); err != nil { - t.Fatalf("failed to register OpenAPI annotations: %s", err) - } - } - result, err := applyTemplate(param{File: fileCL, reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - if want, is, name := "2.0", result.Swagger, "Swagger"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if got, want := len(result.extensions), 2; got != want { - t.Fatalf("len(applyTemplate(%#v).Extensions) = %d want to be %d", file, got, want) - } - if got, want := result.extensions[0].key, "x-bar"; got != want { - t.Errorf("applyTemplate(%#v).Extensions[0].key = %s want to be %s", file, got, want) - } - if got, want := result.extensions[1].key, "x-foo"; got != want { - t.Errorf("applyTemplate(%#v).Extensions[1].key = %s want to be %s", file, got, want) - } - { - var got []string - err = marshaler.Unmarshal(result.extensions[0].value, &got) - if err != nil { - t.Fatalf("marshaler.Unmarshal failed: %v", err) - } - want := []string{"baz"} - if diff := cmp.Diff(got, want); diff != "" { - t.Errorf(diff) - } - } - { - var got string - err = marshaler.Unmarshal(result.extensions[1].value, &got) - if err != nil { - t.Fatalf("marshaler.Unmarshal failed: %v", err) - } - want := "bar" - if diff := cmp.Diff(got, want); diff != "" { - t.Errorf(diff) - } - } - - var scheme openapiSecuritySchemeObject - for _, v := range result.SecurityDefinitions { - scheme = v - } - if want, is, name := []extension{ - {key: "x-security-baz", value: json.RawMessage("true")}, - }, scheme.extensions, "SecurityScheme.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - - if want, is, name := []extension{ - {key: "x-info-extension", value: json.RawMessage("\"bar\"")}, - }, result.Info.extensions, "Info.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - - var operation *openapiOperationObject - var response openapiResponseObject - for _, v := range result.Paths { - operation = v.Get - response = v.Get.Responses["200"] - } - if want, is, name := []extension{ - {key: "x-op-foo", value: json.RawMessage("\"baz\"")}, - }, operation.extensions, "operation.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - if want, is, name := []extension{ - {key: "x-resp-id", value: json.RawMessage("\"resp1000\"")}, - }, response.extensions, "response.Extensions"; !reflect.DeepEqual(is, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, is, want) - } - } - t.Run("verify template options set via proto options", func(t *testing.T) { - file := newFile() - proto.SetExtension(proto.Message(file.FileDescriptorProto.Options), openapi_options.E_Openapiv2Swagger, &swagger) - proto.SetExtension(proto.Message(file.Services[0].Methods[0].Options), openapi_options.E_Openapiv2Operation, &openapiOperation) - reg := descriptor.NewRegistry() - verifyTemplateExtensions(t, reg, file, nil) - }) - t.Run("verify template options set via annotations", func(t *testing.T) { - file := newFile() - opts := &openapiconfig.OpenAPIOptions{ - File: []*openapiconfig.OpenAPIFileOption{ - { - File: "example.proto", - Option: &swagger, - }, - }, - Method: []*openapiconfig.OpenAPIMethodOption{ - { - Method: "example.ExampleService.Example", - Option: &openapiOperation, - }, - }, - } - reg := descriptor.NewRegistry() - verifyTemplateExtensions(t, reg, file, opts) - }) -} - -func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String("NestedMessage"), - Number: proto.Int32(1), - }, - }, - } - nesteddesc := &descriptorpb.DescriptorProto{ - Name: proto.String("NestedMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("int32"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("bool"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(), - Number: proto.Int32(2), - }, - }, - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Echo"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - ClientStreaming: proto.Bool(false), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - meth.ServerStreaming = proto.Bool(false) - - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - nested := &descriptor.Message{ - DescriptorProto: nesteddesc, - } - - nestedField := &descriptor.Field{ - Message: msg, - FieldDescriptorProto: msg.GetField()[0], - } - intField := &descriptor.Field{ - Message: nested, - FieldDescriptorProto: nested.GetField()[0], - } - boolField := &descriptor.Field{ - Message: nested, - FieldDescriptorProto: nested.GetField()[1], - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc, nesteddesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg, nested}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "POST", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew): Figure out what this hsould really be - }, - PathParams: []descriptor.Parameter{ - { - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "nested", - Target: nestedField, - }, - { - Name: "int32", - Target: intField, - }, - }), - Target: intField, - }, - }, - Body: &descriptor.Body{ - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "nested", - Target: nestedField, - }, - { - Name: "bool", - Target: boolField, - }, - }), - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - if want, got := "2.0", result.Swagger; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).Swagger = %s want to be %s", file, got, want) - } - if want, got := "", result.BasePath; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).BasePath = %s want to be %s", file, got, want) - } - if want, got := ([]string)(nil), result.Schemes; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).Schemes = %s want to be %s", file, got, want) - } - if want, got := []string{"application/json"}, result.Consumes; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).Consumes = %s want to be %s", file, got, want) - } - if want, got := []string{"application/json"}, result.Produces; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).Produces = %s want to be %s", file, got, want) - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("nested"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String("NestedMessage"), - Number: proto.Int32(1), - }, - }, - } - nesteddesc := &descriptorpb.DescriptorProto{ - Name: proto.String("NestedMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("int32"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("bool"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(), - Number: proto.Int32(2), - }, - }, - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Echo"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - ClientStreaming: proto.Bool(true), - ServerStreaming: proto.Bool(true), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - nested := &descriptor.Message{ - DescriptorProto: nesteddesc, - } - - nestedField := &descriptor.Field{ - Message: msg, - FieldDescriptorProto: msg.GetField()[0], - } - intField := &descriptor.Field{ - Message: nested, - FieldDescriptorProto: nested.GetField()[0], - } - boolField := &descriptor.Field{ - Message: nested, - FieldDescriptorProto: nested.GetField()[1], - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc, nesteddesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg, nested}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "POST", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", // TODO(achew): Figure out what this hsould really be - }, - PathParams: []descriptor.Parameter{ - { - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "nested", - Target: nestedField, - }, - { - Name: "int32", - Target: intField, - }, - }), - Target: intField, - }, - }, - Body: &descriptor.Body{ - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "nested", - Target: nestedField, - }, - { - Name: "bool", - Target: boolField, - }, - }), - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - - // Only ExampleMessage must be present, not NestedMessage - if want, got, name := 3, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) - } - if _, ok := result.Paths["/v1/echo"].Post.Responses["200"]; !ok { - t.Errorf("applyTemplate(%#v).%s = expected 200 response to be defined", file, `result.Paths["/v1/echo"].Post.Responses["200"]`) - } else { - if want, got, name := "A successful response.(streaming responses)", result.Paths["/v1/echo"].Post.Responses["200"].Description, `result.Paths["/v1/echo"].Post.Responses["200"].Description`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - streamExampleExampleMessage := result.Paths["/v1/echo"].Post.Responses["200"].Schema - if want, got, name := "object", streamExampleExampleMessage.Type, `result.Paths["/v1/echo"].Post.Responses["200"].Schema.Type`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - if want, got, name := "Stream result of exampleExampleMessage", streamExampleExampleMessage.Title, `result.Paths["/v1/echo"].Post.Responses["200"].Schema.Title`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - streamExampleExampleMessageProperties := *(streamExampleExampleMessage.Properties) - if want, got, name := 2, len(streamExampleExampleMessageProperties), `len(StreamDefinitions["exampleExampleMessage"].Properties)`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) - } else { - resultProperty := streamExampleExampleMessageProperties[0] - if want, got, name := "result", resultProperty.Key, `(*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Key`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - result := resultProperty.Value.(openapiSchemaObject) - if want, got, name := "#/definitions/exampleExampleMessage", result.Ref, `((*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Value.(openapiSchemaObject)).Ref`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - errorProperty := streamExampleExampleMessageProperties[1] - if want, got, name := "error", errorProperty.Key, `(*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Key`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - err := errorProperty.Value.(openapiSchemaObject) - if want, got, name := "#/definitions/rpcStatus", err.Ref, `((*(StreamDefinitions["exampleExampleMessage"].Properties))[0].Value.(openapiSchemaObject)).Ref`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want) - } - } - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func TestApplyTemplateRequestWithUnusedReferences(t *testing.T) { - reqdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("string"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - }, - } - respdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("EmptyMessage"), - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Example"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("EmptyMessage"), - ClientStreaming: proto.Bool(false), - ServerStreaming: proto.Bool(false), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - req := &descriptor.Message{ - DescriptorProto: reqdesc, - } - resp := &descriptor.Message{ - DescriptorProto: respdesc, - } - stringField := &descriptor.Field{ - Message: req, - FieldDescriptorProto: req.GetField()[0], - } - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{reqdesc, respdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{req, resp}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: req, - ResponseType: resp, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "GET", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/example", - }, - }, - { - HTTPMethod: "POST", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/example/{string}", - }, - PathParams: []descriptor.Parameter{ - { - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "string", - Target: stringField, - }, - }), - Target: stringField, - }, - }, - Body: &descriptor.Body{ - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "string", - Target: stringField, - }, - }), - }, - }, - }, - }, - }, - }, - }, - } - - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - - // Only EmptyMessage must be present, not ExampleMessage (plus error status) - if want, got, name := 3, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func TestApplyTemplateRequestWithBodyQueryParameters(t *testing.T) { - bookDesc := &descriptorpb.DescriptorProto{ - Name: proto.String("Book"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("name"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("id"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(2), - }, - }, - } - createDesc := &descriptorpb.DescriptorProto{ - Name: proto.String("CreateBookRequest"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("parent"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("book"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(2), - }, - { - Name: proto.String("book_id"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(3), - }, - }, - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("CreateBook"), - InputType: proto.String("CreateBookRequest"), - OutputType: proto.String("Book"), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("BookService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - bookMsg := &descriptor.Message{ - DescriptorProto: bookDesc, - } - createMsg := &descriptor.Message{ - DescriptorProto: createDesc, - } - - parentField := &descriptor.Field{ - Message: createMsg, - FieldDescriptorProto: createMsg.GetField()[0], - } - bookField := &descriptor.Field{ - Message: createMsg, - FieldMessage: bookMsg, - FieldDescriptorProto: createMsg.GetField()[1], - } - bookIDField := &descriptor.Field{ - Message: createMsg, - FieldDescriptorProto: createMsg.GetField()[2], - } - - createMsg.Fields = []*descriptor.Field{parentField, bookField, bookIDField} - - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("book.proto"), - MessageType: []*descriptorpb.DescriptorProto{bookDesc, createDesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/book.pb", - Name: "book_pb", - }, - Messages: []*descriptor.Message{bookMsg, createMsg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: createMsg, - ResponseType: bookMsg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "POST", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/{parent=publishers/*}/books", - }, - PathParams: []descriptor.Parameter{ - { - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "parent", - Target: parentField, - }, - }), - Target: parentField, - }, - }, - Body: &descriptor.Body{ - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{ - { - Name: "book", - Target: bookField, - }, - }), - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - if err := AddErrorDefs(reg); err != nil { - t.Errorf("AddErrorDefs(%#v) failed with %v; want success", reg, err) - return - } - err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) - if err != nil { - t.Errorf("Registry.Load() failed with %v; want success", err) - return - } - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - - if _, ok := result.Paths["/v1/{parent=publishers/*}/books"].Post.Responses["200"]; !ok { - t.Errorf("applyTemplate(%#v).%s = expected 200 response to be defined", file, `result.Paths["/v1/{parent=publishers/*}/books"].Post.Responses["200"]`) - } else { - if want, got, name := 3, len(result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters), `len(result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters)`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want) - } - - type param struct { - Name string - In string - Required bool - } - - p0 := result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[0] - if want, got, name := (param{"parent", "path", true}), (param{p0.Name, p0.In, p0.Required}), `result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[0]`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %v want to be %v", file, name, got, want) - } - p1 := result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[1] - if want, got, name := (param{"body", "body", true}), (param{p1.Name, p1.In, p1.Required}), `result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[1]`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %v want to be %v", file, name, got, want) - } - p2 := result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[2] - if want, got, name := (param{"book_id", "query", false}), (param{p2.Name, p2.In, p2.Required}), `result.Paths["/v1/{parent=publishers/*}/books"].Post.Parameters[1]`; !reflect.DeepEqual(got, want) { - t.Errorf("applyTemplate(%#v).%s = %v want to be %v", file, name, got, want) - } - } - - // If there was a failure, print out the input and the json result for debugging. - if t.Failed() { - t.Errorf("had: %s", file) - t.Errorf("got: %s", fmt.Sprint(result)) - } -} - -func generateFieldsForJSONReservedName() []*descriptor.Field { - fields := make([]*descriptor.Field, 0) - fieldName := string("json_name") - fieldJSONName := string("jsonNAME") - fieldDescriptor := descriptorpb.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName} - field := &descriptor.Field{FieldDescriptorProto: &fieldDescriptor} - return append(fields, field) -} - -func generateMsgsForJSONReservedName() []*descriptor.Message { - result := make([]*descriptor.Message, 0) - // The first message, its field is field_abc and its type is NewType - // NewType field_abc - fieldName := "field_abc" - fieldJSONName := "fieldAbc" - messageName1 := "message1" - messageType := "pkg.a.NewType" - pfd := descriptorpb.FieldDescriptorProto{Name: &fieldName, JsonName: &fieldJSONName, TypeName: &messageType} - result = append(result, - &descriptor.Message{ - DescriptorProto: &descriptorpb.DescriptorProto{ - Name: &messageName1, Field: []*descriptorpb.FieldDescriptorProto{&pfd}, - }, - }) - // The second message, its name is NewName, its type is string - // message NewType { - // string field_newName [json_name = RESERVEDJSONNAME] - // } - messageName := "NewType" - field := "field_newName" - fieldJSONName2 := "RESERVEDJSONNAME" - pfd2 := descriptorpb.FieldDescriptorProto{Name: &field, JsonName: &fieldJSONName2} - result = append(result, &descriptor.Message{ - DescriptorProto: &descriptorpb.DescriptorProto{ - Name: &messageName, Field: []*descriptorpb.FieldDescriptorProto{&pfd2}, - }, - }) - return result -} - -func TestTemplateWithJsonCamelCase(t *testing.T) { - var tests = []struct { - input string - expected string - }{ - {"/test/{test_id}", "/test/{testId}"}, - {"/test1/{test1_id}/test2/{test2_id}", "/test1/{test1Id}/test2/{test2Id}"}, - {"/test1/{test1_id}/{test2_id}", "/test1/{test1Id}/{test2Id}"}, - {"/test1/test2/{test1_id}/{test2_id}", "/test1/test2/{test1Id}/{test2Id}"}, - {"/test1/{test1_id1_id2}", "/test1/{test1Id1Id2}"}, - {"/test1/{test1_id1_id2}/test2/{test2_id3_id4}", "/test1/{test1Id1Id2}/test2/{test2Id3Id4}"}, - {"/test1/test2/{test1_id1_id2}/{test2_id3_id4}", "/test1/test2/{test1Id1Id2}/{test2Id3Id4}"}, - {"test/{a}", "test/{a}"}, - {"test/{ab}", "test/{ab}"}, - {"test/{a_a}", "test/{aA}"}, - {"test/{ab_c}", "test/{abC}"}, - {"test/{json_name}", "test/{jsonNAME}"}, - {"test/{field_abc.field_newName}", "test/{fieldAbc.RESERVEDJSONNAME}"}, - } - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(true) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } -} - -func TestTemplateWithoutJsonCamelCase(t *testing.T) { - var tests = []struct { - input string - expected string - }{ - {"/test/{test_id}", "/test/{test_id}"}, - {"/test1/{test1_id}/test2/{test2_id}", "/test1/{test1_id}/test2/{test2_id}"}, - {"/test1/{test1_id}/{test2_id}", "/test1/{test1_id}/{test2_id}"}, - {"/test1/test2/{test1_id}/{test2_id}", "/test1/test2/{test1_id}/{test2_id}"}, - {"/test1/{test1_id1_id2}", "/test1/{test1_id1_id2}"}, - {"/test1/{test1_id1_id2}/test2/{test2_id3_id4}", "/test1/{test1_id1_id2}/test2/{test2_id3_id4}"}, - {"/test1/test2/{test1_id1_id2}/{test2_id3_id4}", "/test1/test2/{test1_id1_id2}/{test2_id3_id4}"}, - {"test/{a}", "test/{a}"}, - {"test/{ab}", "test/{ab}"}, - {"test/{a_a}", "test/{a_a}"}, - {"test/{json_name}", "test/{json_name}"}, - {"test/{field_abc.field_newName}", "test/{field_abc.field_newName}"}, - } - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(false) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } -} - -func TestTemplateToOpenAPIPath(t *testing.T) { - var tests = []struct { - input string - expected string - }{ - {"/test", "/test"}, - {"/{test}", "/{test}"}, - {"/{test=prefix/*}", "/{test}"}, - {"/{test=prefix/that/has/multiple/parts/to/it/*}", "/{test}"}, - {"/{test1}/{test2}", "/{test1}/{test2}"}, - {"/{test1}/{test2}/", "/{test1}/{test2}/"}, - {"/{name=prefix/*}", "/{name=prefix/*}"}, - {"/{name=prefix1/*/prefix2/*}", "/{name=prefix1/*/prefix2/*}"}, - {"/{user.name=prefix/*}", "/{user.name=prefix/*}"}, - {"/{user.name=prefix1/*/prefix2/*}", "/{user.name=prefix1/*/prefix2/*}"}, - {"/{parent=prefix/*}/children", "/{parent=prefix/*}/children"}, - {"/{name=prefix/*}:customMethod", "/{name=prefix/*}:customMethod"}, - {"/{name=prefix1/*/prefix2/*}:customMethod", "/{name=prefix1/*/prefix2/*}:customMethod"}, - {"/{user.name=prefix/*}:customMethod", "/{user.name=prefix/*}:customMethod"}, - {"/{user.name=prefix1/*/prefix2/*}:customMethod", "/{user.name=prefix1/*/prefix2/*}:customMethod"}, - {"/{parent=prefix/*}/children:customMethod", "/{parent=prefix/*}/children:customMethod"}, - } - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(false) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } - reg.SetUseJSONNamesForFields(true) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } -} - -func BenchmarkTemplateToOpenAPIPath(b *testing.B) { - const input = "/{user.name=prefix1/*/prefix2/*}:customMethod" - - b.Run("with JSON names", func(b *testing.B) { - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(false) - - for i := 0; i < b.N; i++ { - _ = templateToOpenAPIPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - } - }) - - b.Run("without JSON names", func(b *testing.B) { - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(true) - - for i := 0; i < b.N; i++ { - _ = templateToOpenAPIPath(input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - } - }) -} - -func TestResolveFullyQualifiedNameToOpenAPIName(t *testing.T) { - var tests = []struct { - input string - output string - listOfFQMNs []string - useFQNForOpenAPIName bool - }{ - { - ".a.b.C", - "C", - []string{ - ".a.b.C", - }, - false, - }, - { - ".a.b.C", - "abC", - []string{ - ".a.C", - ".a.b.C", - }, - false, - }, - { - ".a.b.C", - "abC", - []string{ - ".C", - ".a.C", - ".a.b.C", - }, - false, - }, - { - ".a.b.C", - "a.b.C", - []string{ - ".C", - ".a.C", - ".a.b.C", - }, - true, - }, - } - - for _, data := range tests { - names := resolveFullyQualifiedNameToOpenAPINames(data.listOfFQMNs, data.useFQNForOpenAPIName) - output := names[data.input] - if output != data.output { - t.Errorf("Expected fullyQualifiedNameToOpenAPIName(%v) to be %s but got %s", - data.input, data.output, output) - } - } -} - -func TestFQMNtoOpenAPIName(t *testing.T) { - var tests = []struct { - input string - expected string - }{ - {"/test", "/test"}, - {"/{test}", "/{test}"}, - {"/{test=prefix/*}", "/{test}"}, - {"/{test=prefix/that/has/multiple/parts/to/it/*}", "/{test}"}, - {"/{test1}/{test2}", "/{test1}/{test2}"}, - {"/{test1}/{test2}/", "/{test1}/{test2}/"}, - } - reg := descriptor.NewRegistry() - reg.SetUseJSONNamesForFields(false) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } - reg.SetUseJSONNamesForFields(true) - for _, data := range tests { - actual := templateToOpenAPIPath(data.input, reg, generateFieldsForJSONReservedName(), generateMsgsForJSONReservedName()) - if data.expected != actual { - t.Errorf("Expected templateToOpenAPIPath(%v) = %v, actual: %v", data.input, data.expected, actual) - } - } -} - -func TestSchemaOfField(t *testing.T) { - type test struct { - field *descriptor.Field - refs refMap - expected openapiSchemaObject - openAPIOptions *openapiconfig.OpenAPIOptions - } - - jsonSchema := &openapi_options.JSONSchema{ - Title: "field title", - Description: "field description", - } - - var fieldOptions = new(descriptorpb.FieldOptions) - proto.SetExtension(fieldOptions, openapi_options.E_Openapiv2Field, jsonSchema) - - tests := []test{ - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("primitive_field"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("repeated_primitive_field"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: &openapiItemsObject{ - Type: "string", - }, - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.FieldMask"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: &openapiItemsObject{ - Type: "string", - }, - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Timestamp"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - Format: "date-time", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Duration"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.StringValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("repeated_wrapped_field"), - TypeName: proto.String(".google.protobuf.StringValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: &openapiItemsObject{ - Type: "string", - }, - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.BytesValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - Format: "byte", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Int32Value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "integer", - Format: "int32", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.UInt32Value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "integer", - Format: "int64", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Int64Value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - Format: "int64", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.UInt64Value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - Format: "uint64", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.FloatValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "number", - Format: "float", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.DoubleValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "number", - Format: "double", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.BoolValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "boolean", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Struct"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "object", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.Value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "object", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.ListValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: (*openapiItemsObject)(&schemaCore{ - Type: "object", - }), - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("wrapped_field"), - TypeName: proto.String(".google.protobuf.NullValue"), - Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(), - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "string", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("message_field"), - TypeName: proto.String(".example.Message"), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - }, - }, - refs: refMap{".example.Message": struct{}{}}, - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Ref: "#/definitions/exampleMessage", - }, - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("map_field"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Message.MapFieldEntry"), - Options: fieldOptions, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "object", - }, - AdditionalProperties: &openapiSchemaObject{ - schemaCore: schemaCore{Type: "string"}, - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("array_field"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Options: fieldOptions, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: (*openapiItemsObject)(&schemaCore{Type: "string"}), - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("primitive_field"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), - Options: fieldOptions, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "integer", - Format: "int32", - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("message_field"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Empty"), - Options: fieldOptions, - }, - }, - refs: refMap{".example.Empty": struct{}{}}, - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Ref: "#/definitions/exampleEmpty", - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("map_field"), // should be called map_field_option but it's not valid map field name - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Message.MapFieldEntry"), - }, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Field: []*openapiconfig.OpenAPIFieldOption{ - { - Field: "example.Message.map_field", - Option: jsonSchema, - }, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "object", - }, - AdditionalProperties: &openapiSchemaObject{ - schemaCore: schemaCore{Type: "string"}, - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("array_field_option"), - Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - }, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Field: []*openapiconfig.OpenAPIFieldOption{ - { - Field: "example.Message.array_field_option", - Option: jsonSchema, - }, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "array", - Items: (*openapiItemsObject)(&schemaCore{Type: "string"}), - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("primitive_field_option"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(), - }, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Field: []*openapiconfig.OpenAPIFieldOption{ - { - Field: "example.Message.primitive_field_option", - Option: jsonSchema, - }, - }, - }, - refs: make(refMap), - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Type: "integer", - Format: "int32", - }, - Title: "field title", - Description: "field description", - }, - }, - { - field: &descriptor.Field{ - FieldDescriptorProto: &descriptorpb.FieldDescriptorProto{ - Name: proto.String("message_field_option"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), - TypeName: proto.String(".example.Empty"), - }, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Field: []*openapiconfig.OpenAPIFieldOption{ - { - Field: "example.Message.message_field_option", - Option: jsonSchema, - }, - }, - }, - refs: refMap{".example.Empty": struct{}{}}, - expected: openapiSchemaObject{ - schemaCore: schemaCore{ - Ref: "#/definitions/exampleEmpty", - }, - Title: "field title", - Description: "field description", - }, - }, - } - for _, test := range tests { - reg := descriptor.NewRegistry() - req := &pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{ - { - Name: proto.String("third_party/google.proto"), - Package: proto.String("google.protobuf"), - MessageType: []*descriptorpb.DescriptorProto{ - protodesc.ToDescriptorProto((&structpb.Struct{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&structpb.Value{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&structpb.ListValue{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&field_mask.FieldMask{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((×tamppb.Timestamp{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&durationpb.Duration{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.StringValue{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.BytesValue{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.Int32Value{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.UInt32Value{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.Int64Value{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.UInt64Value{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.FloatValue{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.DoubleValue{}).ProtoReflect().Descriptor()), - protodesc.ToDescriptorProto((&wrapperspb.BoolValue{}).ProtoReflect().Descriptor()), - }, - EnumType: []*descriptorpb.EnumDescriptorProto{ - protodesc.ToEnumDescriptorProto(structpb.NullValue(0).Descriptor()), - }, - }, - { - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{"third_party/google.proto"}, - MessageType: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("Message"), - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("value"), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - func() *descriptorpb.FieldDescriptorProto { - fd := test.field.FieldDescriptorProto - fd.Number = proto.Int32(2) - return fd - }(), - }, - NestedType: []*descriptorpb.DescriptorProto{ - { - Name: proto.String("MapFieldEntry"), - Options: &descriptorpb.MessageOptions{MapEntry: proto.Bool(true)}, - Field: []*descriptorpb.FieldDescriptorProto{ - { - Name: proto.String("key"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(1), - }, - { - Name: proto.String("value"), - Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), - Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), - Number: proto.Int32(2), - }, - }, - }, - }, - }, - { - Name: proto.String("Empty"), - }, - }, - EnumType: []*descriptorpb.EnumDescriptorProto{ - { - Name: proto.String("MessageType"), - Value: []*descriptorpb.EnumValueDescriptorProto{ - { - Name: proto.String("MESSAGE_TYPE_1"), - Number: proto.Int32(0), - }, - }, - }, - }, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - }, - } - err := reg.Load(req) - if err != nil { - t.Errorf("failed to reg.Load(req): %v", err) - } - - // set field's parent message pointer to message so field can resolve its FQFN - test.field.Message = &descriptor.Message{ - DescriptorProto: req.ProtoFile[1].MessageType[0], - File: &descriptor.File{ - FileDescriptorProto: req.ProtoFile[1], - }, - } - - if test.openAPIOptions != nil { - if err := reg.RegisterOpenAPIOptions(test.openAPIOptions); err != nil { - t.Fatalf("failed to register OpenAPI options: %s", err) - } - } - - refs := make(refMap) - actual := schemaOfField(test.field, reg, refs) - expectedSchemaObject := test.expected - if e, a := expectedSchemaObject, actual; !reflect.DeepEqual(a, e) { - t.Errorf("Expected schemaOfField(%v) = \n%#+v, actual: \n%#+v", test.field, e, a) - } - if !reflect.DeepEqual(refs, test.refs) { - t.Errorf("Expected schemaOfField(%v) to add refs %v, not %v", test.field, test.refs, refs) - } - } -} - -func TestRenderMessagesAsDefinition(t *testing.T) { - - tests := []struct { - descr string - msgDescs []*descriptorpb.DescriptorProto - schema map[string]openapi_options.Schema // per-message schema to add - defs openapiDefinitionsObject - openAPIOptions *openapiconfig.OpenAPIOptions - }{ - { - descr: "no OpenAPI options", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{}, - defs: map[string]openapiSchemaObject{ - "Message": {schemaCore: schemaCore{Type: "object"}}, - }, - }, - { - descr: "example option", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - Example: `{"foo":"bar"}`, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": {schemaCore: schemaCore{ - Type: "object", - Example: json.RawMessage(`{"foo":"bar"}`), - }}, - }, - }, - { - descr: "example option with something non-json", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - Example: `XXXX anything goes XXXX`, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": {schemaCore: schemaCore{ - Type: "object", - Example: json.RawMessage(`XXXX anything goes XXXX`), - }}, - }, - }, - { - descr: "external docs option", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - ExternalDocs: &openapi_options.ExternalDocumentation{ - Description: "glorious docs", - Url: "https://nada", - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - ExternalDocs: &openapiExternalDocumentationObject{ - Description: "glorious docs", - URL: "https://nada", - }, - }, - }, - }, - { - descr: "JSONSchema options", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - JsonSchema: &openapi_options.JSONSchema{ - Title: "title", - Description: "desc", - MultipleOf: 100, - Maximum: 101, - ExclusiveMaximum: true, - Minimum: 1, - ExclusiveMinimum: true, - MaxLength: 10, - MinLength: 3, - Pattern: "[a-z]+", - MaxItems: 20, - MinItems: 2, - UniqueItems: true, - MaxProperties: 33, - MinProperties: 22, - Required: []string{"req"}, - ReadOnly: true, - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - Title: "title", - Description: "desc", - MultipleOf: 100, - Maximum: 101, - ExclusiveMaximum: true, - Minimum: 1, - ExclusiveMinimum: true, - MaxLength: 10, - MinLength: 3, - Pattern: "[a-z]+", - MaxItems: 20, - MinItems: 2, - UniqueItems: true, - MaxProperties: 33, - MinProperties: 22, - Required: []string{"req"}, - ReadOnly: true, - }, - }, - }, - { - descr: "JSONSchema options from registry", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Message: []*openapiconfig.OpenAPIMessageOption{ - { - Message: "example.Message", - Option: &openapi_options.Schema{ - JsonSchema: &openapi_options.JSONSchema{ - Title: "title", - Description: "desc", - MultipleOf: 100, - Maximum: 101, - ExclusiveMaximum: true, - Minimum: 1, - ExclusiveMinimum: true, - MaxLength: 10, - MinLength: 3, - Pattern: "[a-z]+", - MaxItems: 20, - MinItems: 2, - UniqueItems: true, - MaxProperties: 33, - MinProperties: 22, - Required: []string{"req"}, - ReadOnly: true, - }, - }, - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - Title: "title", - Description: "desc", - MultipleOf: 100, - Maximum: 101, - ExclusiveMaximum: true, - Minimum: 1, - ExclusiveMinimum: true, - MaxLength: 10, - MinLength: 3, - Pattern: "[a-z]+", - MaxItems: 20, - MinItems: 2, - UniqueItems: true, - MaxProperties: 33, - MinProperties: 22, - Required: []string{"req"}, - ReadOnly: true, - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.descr, func(t *testing.T) { - - msgs := []*descriptor.Message{} - for _, msgdesc := range test.msgDescs { - msgdesc.Options = &descriptorpb.MessageOptions{} - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - - reg := descriptor.NewRegistry() - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.msgDescs, - EnumType: []*descriptorpb.EnumDescriptorProto{}, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - msgMap := map[string]*descriptor.Message{} - for _, d := range test.msgDescs { - name := d.GetName() - msg, err := reg.LookupMsg("example", name) - if err != nil { - t.Fatalf("lookup message %v: %v", name, err) - } - msgMap[msg.FQMN()] = msg - - if schema, ok := test.schema[name]; ok { - proto.SetExtension(d.Options, openapi_options.E_Openapiv2Schema, &schema) - } - } - - if test.openAPIOptions != nil { - if err := reg.RegisterOpenAPIOptions(test.openAPIOptions); err != nil { - t.Fatalf("failed to register OpenAPI options: %s", err) - } - } - - refs := make(refMap) - actual := make(openapiDefinitionsObject) - renderMessagesAsDefinition(msgMap, actual, reg, refs) - - if !reflect.DeepEqual(actual, test.defs) { - t.Errorf("Expected renderMessagesAsDefinition() to add defs %+v, not %+v", test.defs, actual) - } - }) - } -} - -func TestUpdateOpenAPIDataFromComments(t *testing.T) { - - tests := []struct { - descr string - openapiSwaggerObject interface{} - comments string - expectedError error - expectedOpenAPIObject interface{} - useGoTemplate bool - }{ - { - descr: "empty comments", - openapiSwaggerObject: nil, - expectedOpenAPIObject: nil, - comments: "", - expectedError: nil, - }, - { - descr: "set field to read only", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - ReadOnly: true, - Description: "... Output only. ...", - }, - comments: "... Output only. ...", - expectedError: nil, - }, - { - descr: "set title", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Title: "Comment with no trailing dot", - }, - comments: "Comment with no trailing dot", - expectedError: nil, - }, - { - descr: "set description", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Description: "Comment with trailing dot.", - }, - comments: "Comment with trailing dot.", - expectedError: nil, - }, - { - descr: "use info object", - openapiSwaggerObject: &openapiSwaggerObject{ - Info: openapiInfoObject{}, - }, - expectedOpenAPIObject: &openapiSwaggerObject{ - Info: openapiInfoObject{ - Description: "Comment with trailing dot.", - }, - }, - comments: "Comment with trailing dot.", - expectedError: nil, - }, - { - descr: "multi line comment with title", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Title: "First line", - Description: "Second line", - }, - comments: "First line\n\nSecond line", - expectedError: nil, - }, - { - descr: "multi line comment no title", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Description: "First line.\n\nSecond line", - }, - comments: "First line.\n\nSecond line", - expectedError: nil, - }, - { - descr: "multi line comment with summary with dot", - openapiSwaggerObject: &openapiOperationObject{}, - expectedOpenAPIObject: &openapiOperationObject{ - Summary: "First line.", - Description: "Second line", - }, - comments: "First line.\n\nSecond line", - expectedError: nil, - }, - { - descr: "multi line comment with summary no dot", - openapiSwaggerObject: &openapiOperationObject{}, - expectedOpenAPIObject: &openapiOperationObject{ - Summary: "First line", - Description: "Second line", - }, - comments: "First line\n\nSecond line", - expectedError: nil, - }, - { - descr: "multi line comment with summary no dot", - openapiSwaggerObject: &schemaCore{}, - expectedOpenAPIObject: &schemaCore{}, - comments: "Any comment", - expectedError: errors.New("no description nor summary property"), - }, - { - descr: "without use_go_template", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Title: "First line", - Description: "{{import \"documentation.md\"}}", - }, - comments: "First line\n\n{{import \"documentation.md\"}}", - expectedError: nil, - }, - { - descr: "error with use_go_template", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Title: "First line", - Description: "open noneexistingfile.txt: no such file or directory", - }, - comments: "First line\n\n{{import \"noneexistingfile.txt\"}}", - expectedError: nil, - useGoTemplate: true, - }, - { - descr: "template with use_go_template", - openapiSwaggerObject: &openapiSchemaObject{}, - expectedOpenAPIObject: &openapiSchemaObject{ - Title: "Template", - Description: `Description "which means nothing"`, - }, - comments: "Template\n\nDescription {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - expectedError: nil, - useGoTemplate: true, - }, - } - - for _, test := range tests { - t.Run(test.descr, func(t *testing.T) { - reg := descriptor.NewRegistry() - if test.useGoTemplate { - reg.SetUseGoTemplate(true) - } - err := updateOpenAPIDataFromComments(reg, test.openapiSwaggerObject, nil, test.comments, false) - if test.expectedError == nil { - if err != nil { - t.Errorf("unexpected error '%v'", err) - } - if !reflect.DeepEqual(test.openapiSwaggerObject, test.expectedOpenAPIObject) { - t.Errorf("openapiSwaggerObject was not updated correctly, expected '%+v', got '%+v'", test.expectedOpenAPIObject, test.openapiSwaggerObject) - } - } else { - if err == nil { - t.Error("expected update error not returned") - } - if !reflect.DeepEqual(test.openapiSwaggerObject, test.expectedOpenAPIObject) { - t.Errorf("openapiSwaggerObject was not updated correctly, expected '%+v', got '%+v'", test.expectedOpenAPIObject, test.openapiSwaggerObject) - } - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error malformed, expected %q, got %q", test.expectedError.Error(), err.Error()) - } - } - }) - } -} - -func TestMessageOptionsWithGoTemplate(t *testing.T) { - tests := []struct { - descr string - msgDescs []*descriptorpb.DescriptorProto - schema map[string]openapi_options.Schema // per-message schema to add - defs openapiDefinitionsObject - openAPIOptions *openapiconfig.OpenAPIOptions - useGoTemplate bool - }{ - { - descr: "external docs option", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - JsonSchema: &openapi_options.JSONSchema{ - Title: "{{.Name}}", - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - ExternalDocs: &openapi_options.ExternalDocumentation{ - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - Title: "Message", - Description: `Description "which means nothing"`, - ExternalDocs: &openapiExternalDocumentationObject{ - Description: `Description "which means nothing"`, - }, - }, - }, - useGoTemplate: true, - }, - { - descr: "external docs option", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - schema: map[string]openapi_options.Schema{ - "Message": { - JsonSchema: &openapi_options.JSONSchema{ - Title: "{{.Name}}", - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - ExternalDocs: &openapi_options.ExternalDocumentation{ - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - Title: "{{.Name}}", - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - ExternalDocs: &openapiExternalDocumentationObject{ - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - }, - }, - useGoTemplate: false, - }, - { - descr: "registered OpenAPIOption", - msgDescs: []*descriptorpb.DescriptorProto{ - {Name: proto.String("Message")}, - }, - openAPIOptions: &openapiconfig.OpenAPIOptions{ - Message: []*openapiconfig.OpenAPIMessageOption{ - { - Message: "example.Message", - Option: &openapi_options.Schema{ - JsonSchema: &openapi_options.JSONSchema{ - Title: "{{.Name}}", - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - ExternalDocs: &openapi_options.ExternalDocumentation{ - Description: "Description {{with \"which means nothing\"}}{{printf \"%q\" .}}{{end}}", - }, - }, - }, - }, - }, - defs: map[string]openapiSchemaObject{ - "Message": { - schemaCore: schemaCore{ - Type: "object", - }, - Title: "Message", - Description: `Description "which means nothing"`, - ExternalDocs: &openapiExternalDocumentationObject{ - Description: `Description "which means nothing"`, - }, - }, - }, - useGoTemplate: true, - }, - } - - for _, test := range tests { - t.Run(test.descr, func(t *testing.T) { - - msgs := []*descriptor.Message{} - for _, msgdesc := range test.msgDescs { - msgdesc.Options = &descriptorpb.MessageOptions{} - msgs = append(msgs, &descriptor.Message{DescriptorProto: msgdesc}) - } - - reg := descriptor.NewRegistry() - reg.SetUseGoTemplate(test.useGoTemplate) - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - Dependency: []string{}, - MessageType: test.msgDescs, - EnumType: []*descriptorpb.EnumDescriptorProto{}, - Service: []*descriptorpb.ServiceDescriptorProto{}, - }, - Messages: msgs, - } - reg.Load(&pluginpb.CodeGeneratorRequest{ - ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}, - }) - - msgMap := map[string]*descriptor.Message{} - for _, d := range test.msgDescs { - name := d.GetName() - msg, err := reg.LookupMsg("example", name) - if err != nil { - t.Fatalf("lookup message %v: %v", name, err) - } - msgMap[msg.FQMN()] = msg - - if schema, ok := test.schema[name]; ok { - proto.SetExtension(d.Options, openapi_options.E_Openapiv2Schema, &schema) - } - } - - if test.openAPIOptions != nil { - if err := reg.RegisterOpenAPIOptions(test.openAPIOptions); err != nil { - t.Fatalf("failed to register OpenAPI options: %s", err) - } - } - - refs := make(refMap) - actual := make(openapiDefinitionsObject) - renderMessagesAsDefinition(msgMap, actual, reg, refs) - - if !reflect.DeepEqual(actual, test.defs) { - t.Errorf("Expected renderMessagesAsDefinition() to add defs %+v, not %+v", test.defs, actual) - } - }) - } -} - -func TestTemplateWithoutErrorDefinition(t *testing.T) { - msgdesc := &descriptorpb.DescriptorProto{ - Name: proto.String("ExampleMessage"), - Field: []*descriptorpb.FieldDescriptorProto{}, - } - meth := &descriptorpb.MethodDescriptorProto{ - Name: proto.String("Echo"), - InputType: proto.String("ExampleMessage"), - OutputType: proto.String("ExampleMessage"), - } - svc := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("ExampleService"), - Method: []*descriptorpb.MethodDescriptorProto{meth}, - } - - msg := &descriptor.Message{ - DescriptorProto: msgdesc, - } - - file := descriptor.File{ - FileDescriptorProto: &descriptorpb.FileDescriptorProto{ - SourceCodeInfo: &descriptorpb.SourceCodeInfo{}, - Name: proto.String("example.proto"), - Package: proto.String("example"), - MessageType: []*descriptorpb.DescriptorProto{msgdesc}, - Service: []*descriptorpb.ServiceDescriptorProto{svc}, - }, - GoPkg: descriptor.GoPackage{ - Path: "example.com/path/to/example/example.pb", - Name: "example_pb", - }, - Messages: []*descriptor.Message{msg}, - Services: []*descriptor.Service{ - { - ServiceDescriptorProto: svc, - Methods: []*descriptor.Method{ - { - MethodDescriptorProto: meth, - RequestType: msg, - ResponseType: msg, - Bindings: []*descriptor.Binding{ - { - HTTPMethod: "POST", - PathTmpl: httprule.Template{ - Version: 1, - OpCodes: []int{0, 0}, - Template: "/v1/echo", - }, - Body: &descriptor.Body{ - FieldPath: descriptor.FieldPath([]descriptor.FieldPathComponent{}), - }, - }, - }, - }, - }, - }, - }, - } - reg := descriptor.NewRegistry() - err := reg.Load(&pluginpb.CodeGeneratorRequest{ProtoFile: []*descriptorpb.FileDescriptorProto{file.FileDescriptorProto}}) - if err != nil { - t.Errorf("failed to reg.Load(): %v", err) - return - } - result, err := applyTemplate(param{File: crossLinkFixture(&file), reg: reg}) - if err != nil { - t.Errorf("applyTemplate(%#v) failed with %v; want success", file, err) - return - } - - defRsp, ok := result.Paths["/v1/echo"].Post.Responses["default"] - if !ok { - return - } - - ref := defRsp.Schema.schemaCore.Ref - refName := strings.TrimPrefix(ref, "#/definitions/") - if refName == "" { - t.Fatal("created default Error response with empty reflink") - } - - if _, ok := result.Definitions[refName]; !ok { - t.Errorf("default Error response with reflink '%v', but its definition was not found", refName) - } -} - -func Test_getReservedJsonName(t *testing.T) { - type args struct { - fieldName string - messageNameToFieldsToJSONName map[string]map[string]string - fieldNameToType map[string]string - } - tests := []struct { - name string - args args - want string - }{ - { - "test case 1: single dot use case", - args{ - fieldName: "abc.a_1", - messageNameToFieldsToJSONName: map[string]map[string]string{ - "Msg": { - "a_1": "a1JSONNAME", - "b_1": "b1JSONNAME", - }, - }, - fieldNameToType: map[string]string{ - "abc": "pkg1.test.Msg", - "bcd": "pkg1.test.Msg", - }, - }, - "a1JSONNAME", - }, - { - "test case 2: single dot use case with no existing field", - args{ - fieldName: "abc.d_1", - messageNameToFieldsToJSONName: map[string]map[string]string{ - "Msg": { - "a_1": "a1JSONNAME", - "b_1": "b1JSONNAME", - }, - }, - fieldNameToType: map[string]string{ - "abc": "pkg1.test.Msg", - "bcd": "pkg1.test.Msg", - }, - }, - "", - }, - { - "test case 3: double dot use case", - args{ - fieldName: "pkg.abc.a_1", - messageNameToFieldsToJSONName: map[string]map[string]string{ - "Msg": { - "a_1": "a1JSONNAME", - "b_1": "b1JSONNAME", - }, - }, - fieldNameToType: map[string]string{ - "abc": "pkg1.test.Msg", - "bcd": "pkg1.test.Msg", - }, - }, - "a1JSONNAME", - }, - { - "test case 4: double dot use case with a not existed field", - args{ - fieldName: "pkg.abc.c_1", - messageNameToFieldsToJSONName: map[string]map[string]string{ - "Msg": { - "a_1": "a1JSONNAME", - "b_1": "b1JSONNAME", - }, - }, - fieldNameToType: map[string]string{ - "abc": "pkg1.test.Msg", - "bcd": "pkg1.test.Msg", - }, - }, - "", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := getReservedJSONName(tt.args.fieldName, tt.args.messageNameToFieldsToJSONName, tt.args.fieldNameToType); got != tt.want { - t.Errorf("getReservedJSONName() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go b/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go index 40e7d0f..1155b78 100644 --- a/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go +++ b/gateway/protoc-gen-openapiv2/internal/genopenapi/types.go @@ -8,6 +8,7 @@ import ( // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" options "github.com/binchencoder/ease-gateway/httpoptions" + "gopkg.in/yaml.v2" ) type param struct { @@ -17,57 +18,65 @@ type param struct { // http://swagger.io/specification/#infoObject type openapiInfoObject struct { - Title string `json:"title"` - Description string `json:"description,omitempty"` - TermsOfService string `json:"termsOfService,omitempty"` - Version string `json:"version"` + Title string `json:"title" yaml:"title"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"` + Version string `json:"version" yaml:"version"` - Contact *openapiContactObject `json:"contact,omitempty"` - License *openapiLicenseObject `json:"license,omitempty"` + Contact *openapiContactObject `json:"contact,omitempty" yaml:"contact,omitempty"` + License *openapiLicenseObject `json:"license,omitempty" yaml:"license,omitempty"` - extensions []extension + extensions []extension `json:"-" yaml:"-"` +} + +// https://swagger.io/specification/#tagObject +type openapiTagObject struct { + Name string `json:"name" yaml:"name"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` } // http://swagger.io/specification/#contactObject type openapiContactObject struct { - Name string `json:"name,omitempty"` - URL string `json:"url,omitempty"` - Email string `json:"email,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + URL string `json:"url,omitempty" yaml:"url,omitempty"` + Email string `json:"email,omitempty" yaml:"email,omitempty"` } // http://swagger.io/specification/#licenseObject type openapiLicenseObject struct { - Name string `json:"name,omitempty"` - URL string `json:"url,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + URL string `json:"url,omitempty" yaml:"url,omitempty"` } // http://swagger.io/specification/#externalDocumentationObject type openapiExternalDocumentationObject struct { - Description string `json:"description,omitempty"` - URL string `json:"url,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + URL string `json:"url,omitempty" yaml:"url,omitempty"` } type extension struct { - key string - value json.RawMessage + key string `json:"-" yaml:"-"` + value json.RawMessage `json:"-" yaml:"-"` } // http://swagger.io/specification/#swaggerObject type openapiSwaggerObject struct { - Swagger string `json:"swagger"` - Info openapiInfoObject `json:"info"` - Host string `json:"host,omitempty"` - BasePath string `json:"basePath,omitempty"` - Schemes []string `json:"schemes,omitempty"` - Consumes []string `json:"consumes"` - Produces []string `json:"produces"` - Paths openapiPathsObject `json:"paths"` - Definitions openapiDefinitionsObject `json:"definitions"` - SecurityDefinitions openapiSecurityDefinitionsObject `json:"securityDefinitions,omitempty"` - Security []openapiSecurityRequirementObject `json:"security,omitempty"` - ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"` - - extensions []extension + Swagger string `json:"swagger" yaml:"swagger"` + Info openapiInfoObject `json:"info" yaml:"info"` + Tags []openapiTagObject `json:"tags,omitempty" yaml:"tags,omitempty"` + Host string `json:"host,omitempty" yaml:"host,omitempty"` + BasePath string `json:"basePath,omitempty" yaml:"basePath,omitempty"` + Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` + Consumes []string `json:"consumes" yaml:"consumes"` + Produces []string `json:"produces" yaml:"produces"` + Paths openapiPathsObject `json:"paths" yaml:"paths"` + Definitions openapiDefinitionsObject `json:"definitions" yaml:"definitions"` + SecurityDefinitions openapiSecurityDefinitionsObject `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"` + Security []openapiSecurityRequirementObject `json:"security,omitempty" yaml:"security,omitempty"` + ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + + extensions []extension `json:"-" yaml:"-"` } // http://swagger.io/specification/#securityDefinitionsObject @@ -75,16 +84,16 @@ type openapiSecurityDefinitionsObject map[string]openapiSecuritySchemeObject // http://swagger.io/specification/#securitySchemeObject type openapiSecuritySchemeObject struct { - Type string `json:"type"` - Description string `json:"description,omitempty"` - Name string `json:"name,omitempty"` - In string `json:"in,omitempty"` - Flow string `json:"flow,omitempty"` - AuthorizationURL string `json:"authorizationUrl,omitempty"` - TokenURL string `json:"tokenUrl,omitempty"` - Scopes openapiScopesObject `json:"scopes,omitempty"` - - extensions []extension + Type string `json:"type" yaml:"type"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + In string `json:"in,omitempty" yaml:"in,omitempty"` + Flow string `json:"flow,omitempty" yaml:"flow,omitempty"` + AuthorizationURL string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"` + TokenURL string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"` + Scopes openapiScopesObject `json:"scopes,omitempty" yaml:"scopes,omitempty"` + + extensions []extension `json:"-" yaml:"-"` } // http://swagger.io/specification/#scopesObject @@ -98,69 +107,110 @@ type openapiPathsObject map[string]openapiPathItemObject // http://swagger.io/specification/#pathItemObject type openapiPathItemObject struct { - Get *openapiOperationObject `json:"get,omitempty"` - Delete *openapiOperationObject `json:"delete,omitempty"` - Post *openapiOperationObject `json:"post,omitempty"` - Put *openapiOperationObject `json:"put,omitempty"` - Patch *openapiOperationObject `json:"patch,omitempty"` + Get *openapiOperationObject `json:"get,omitempty" yaml:"get,omitempty"` + Delete *openapiOperationObject `json:"delete,omitempty" yaml:"delete,omitempty"` + Post *openapiOperationObject `json:"post,omitempty" yaml:"post,omitempty"` + Put *openapiOperationObject `json:"put,omitempty" yaml:"put,omitempty"` + Patch *openapiOperationObject `json:"patch,omitempty" yaml:"patch,omitempty"` } // http://swagger.io/specification/#operationObject type openapiOperationObject struct { - Summary string `json:"summary,omitempty"` - Description string `json:"description,omitempty"` - OperationID string `json:"operationId"` - Responses openapiResponsesObject `json:"responses"` - Parameters openapiParametersObject `json:"parameters,omitempty"` - Tags []string `json:"tags,omitempty"` - Deprecated bool `json:"deprecated,omitempty"` - Produces []string `json:"produces,omitempty"` - - Security *[]openapiSecurityRequirementObject `json:"security,omitempty"` - ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"` - - extensions []extension + Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + OperationID string `json:"operationId" yaml:"operationId"` + Responses openapiResponsesObject `json:"responses" yaml:"responses"` + Parameters openapiParametersObject `json:"parameters,omitempty" yaml:"parameters,omitempty"` + Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"` + Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` + Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` + + Security *[]openapiSecurityRequirementObject `json:"security,omitempty" yaml:"security,omitempty"` + ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + + extensions []extension `json:"-" yaml:"-"` } type openapiParametersObject []openapiParameterObject // http://swagger.io/specification/#parameterObject type openapiParameterObject struct { - Name string `json:"name"` - Description string `json:"description,omitempty"` - In string `json:"in,omitempty"` - Required bool `json:"required"` - Type string `json:"type,omitempty"` - Format string `json:"format,omitempty"` - Items *openapiItemsObject `json:"items,omitempty"` - Enum []string `json:"enum,omitempty"` - CollectionFormat string `json:"collectionFormat,omitempty"` - Default string `json:"default,omitempty"` - MinItems *int `json:"minItems,omitempty"` + Name string `json:"name" yaml:"name"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + In string `json:"in,omitempty" yaml:"in,omitempty"` + Required bool `json:"required" yaml:"required"` + Type string `json:"type,omitempty" yaml:"type,omitempty"` + Format string `json:"format,omitempty" yaml:"format,omitempty"` + Items *openapiItemsObject `json:"items,omitempty" yaml:"items,omitempty"` + Enum []string `json:"enum,omitempty" yaml:"enum,omitempty"` + CollectionFormat string `json:"collectionFormat,omitempty" yaml:"collectionFormat,omitempty"` + Default string `json:"default,omitempty" yaml:"default,omitempty"` + MinItems *int `json:"minItems,omitempty" yaml:"minItems,omitempty"` + Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"` // Or you can explicitly refer to another type. If this is defined all // other fields should be empty - Schema *openapiSchemaObject `json:"schema,omitempty"` + Schema *openapiSchemaObject `json:"schema,omitempty" yaml:"schema,omitempty"` } // core part of schema, which is common to itemsObject and schemaObject. -// http://swagger.io/specification/#itemsObject +// http://swagger.io/specification/v2/#itemsObject +// The OAS3 spec (https://swagger.io/specification/#schemaObject) defines the +// `nullable` field as part of a Schema Object. This behavior has been +// "back-ported" to OAS2 as the Specification Extension `x-nullable`, and is +// supported by generation tools such as swagger-codegen and go-swagger. +// For protoc-gen-openapiv3, we'd want to add `nullable` instead. type schemaCore struct { - Type string `json:"type,omitempty"` - Format string `json:"format,omitempty"` - Ref string `json:"$ref,omitempty"` - Example json.RawMessage `json:"example,omitempty"` + Type string `json:"type,omitempty" yaml:"type,omitempty"` + Format string `json:"format,omitempty" yaml:"format,omitempty"` + Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` + XNullable bool `json:"x-nullable,omitempty" yaml:"x-nullable,omitempty"` + Example RawExample `json:"example,omitempty" yaml:"example,omitempty"` - Items *openapiItemsObject `json:"items,omitempty"` + Items *openapiItemsObject `json:"items,omitempty" yaml:"items,omitempty"` // If the item is an enumeration include a list of all the *NAMES* of the // enum values. I'm not sure how well this will work but assuming all enums // start from 0 index it will be great. I don't think that is a good assumption. - Enum []string `json:"enum,omitempty"` - Default string `json:"default,omitempty"` + Enum []string `json:"enum,omitempty" yaml:"enum,omitempty"` + Default string `json:"default,omitempty" yaml:"default,omitempty"` Rules []options.ValidationRule `json:"rules,omitempty"` } +type RawExample json.RawMessage + +func (m RawExample) MarshalJSON() ([]byte, error) { + return (json.RawMessage)(m).MarshalJSON() +} + +func (m *RawExample) UnmarshalJSON(data []byte) error { + return (*json.RawMessage)(m).UnmarshalJSON(data) +} + +// MarshalYAML implements yaml.Marshaler interface. +// +// It converts RawExample to one of yaml-supported types and returns it. +// +// From yaml.Marshaler docs: The Marshaler interface may be implemented +// by types to customize their behavior when being marshaled into a YAML +// document. The returned value is marshaled in place of the original +// value implementing Marshaler. +func (e RawExample) MarshalYAML() (interface{}, error) { + // From docs, json.Unmarshal will store one of next types to data: + // - bool, for JSON booleans; + // - float64, for JSON numbers; + // - string, for JSON strings; + // - []interface{}, for JSON arrays; + // - map[string]interface{}, for JSON objects; + // - nil for JSON null. + var data interface{} + if err := json.Unmarshal(e, &data); err != nil { + return nil, err + } + + return data, nil +} + func (s *schemaCore) setRefFromFQN(ref string, reg *descriptor.Registry) error { name, ok := fullyQualifiedNameToOpenAPIName(ref, reg) if !ok { @@ -177,11 +227,23 @@ type openapiResponsesObject map[string]openapiResponseObject // http://swagger.io/specification/#responseObject type openapiResponseObject struct { - Description string `json:"description"` - Schema openapiSchemaObject `json:"schema"` - Examples map[string]interface{} `json:"examples,omitempty"` + Description string `json:"description" yaml:"description"` + Schema openapiSchemaObject `json:"schema" yaml:"schema"` + Examples map[string]interface{} `json:"examples,omitempty" yaml:"examples,omitempty"` + Headers openapiHeadersObject `json:"headers,omitempty" yaml:"headers,omitempty"` - extensions []extension + extensions []extension `json:"-" yaml:"-"` +} + +type openapiHeadersObject map[string]openapiHeaderObject + +// http://swagger.io/specification/#headerObject +type openapiHeaderObject struct { + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Type string `json:"type,omitempty" yaml:"type,omitempty"` + Format string `json:"format,omitempty" yaml:"format,omitempty"` + Default RawExample `json:"default,omitempty" yaml:"default,omitempty"` + Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"` } type keyVal struct { @@ -191,6 +253,19 @@ type keyVal struct { type openapiSchemaObjectProperties []keyVal +func (p openapiSchemaObjectProperties) MarshalYAML() (interface{}, error) { + ms := make(yaml.MapSlice, len(p)) + + for i, v := range p { + ms[i] = yaml.MapItem{ + Key: v.Key, + Value: v.Value, + } + } + + return ms, nil +} + func (op openapiSchemaObjectProperties) MarshalJSON() ([]byte, error) { var buf bytes.Buffer buf.WriteString("{") @@ -217,31 +292,31 @@ func (op openapiSchemaObjectProperties) MarshalJSON() ([]byte, error) { // http://swagger.io/specification/#schemaObject type openapiSchemaObject struct { - schemaCore + schemaCore `yaml:",inline"` // Properties can be recursively defined - Properties *openapiSchemaObjectProperties `json:"properties,omitempty"` - AdditionalProperties *openapiSchemaObject `json:"additionalProperties,omitempty"` - - Description string `json:"description,omitempty"` - Title string `json:"title,omitempty"` - - ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty"` - - ReadOnly bool `json:"readOnly,omitempty"` - MultipleOf float64 `json:"multipleOf,omitempty"` - Maximum float64 `json:"maximum,omitempty"` - ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"` - Minimum float64 `json:"minimum,omitempty"` - ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"` - MaxLength uint64 `json:"maxLength,omitempty"` - MinLength uint64 `json:"minLength,omitempty"` - Pattern string `json:"pattern,omitempty"` - MaxItems uint64 `json:"maxItems,omitempty"` - MinItems uint64 `json:"minItems,omitempty"` - UniqueItems bool `json:"uniqueItems,omitempty"` - MaxProperties uint64 `json:"maxProperties,omitempty"` - MinProperties uint64 `json:"minProperties,omitempty"` - Required []string `json:"required,omitempty"` + Properties *openapiSchemaObjectProperties `json:"properties,omitempty" yaml:"properties,omitempty"` + AdditionalProperties *openapiSchemaObject `json:"additionalProperties,omitempty" yaml:"additionalProperties,omitempty"` + + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Title string `json:"title,omitempty" yaml:"title,omitempty"` + + ExternalDocs *openapiExternalDocumentationObject `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + + ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"` + MultipleOf float64 `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"` + Maximum float64 `json:"maximum,omitempty" yaml:"maximum,omitempty"` + ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"` + Minimum float64 `json:"minimum,omitempty" yaml:"minimum,omitempty"` + ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty" yaml:"exclusiveMinimum,omitempty"` + MaxLength uint64 `json:"maxLength,omitempty" yaml:"maxLength,omitempty"` + MinLength uint64 `json:"minLength,omitempty" yaml:"minLength,omitempty"` + Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"` + MaxItems uint64 `json:"maxItems,omitempty" yaml:"maxItems,omitempty"` + MinItems uint64 `json:"minItems,omitempty" yaml:"minItems,omitempty"` + UniqueItems bool `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"` + MaxProperties uint64 `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"` + MinProperties uint64 `json:"minProperties,omitempty" yaml:"minProperties,omitempty"` + Required []string `json:"required,omitempty" yaml:"required,omitempty"` } // http://swagger.io/specification/#definitionsObject diff --git a/gateway/protoc-gen-openapiv2/main.go b/gateway/protoc-gen-openapiv2/main.go index e180b06..3e48a20 100644 --- a/gateway/protoc-gen-openapiv2/main.go +++ b/gateway/protoc-gen-openapiv2/main.go @@ -11,31 +11,38 @@ import ( // "github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor" "github.com/binchencoder/ease-gateway/gateway/internal/descriptor" - // genopenapi "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/internal/genopenapi" + // "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/internal/genopenapi" genopenapi "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/internal/genopenapi" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/pluginpb" ) var ( - importPrefix = flag.String("import_prefix", "", "prefix to be added to go package paths for imported proto files") - file = flag.String("file", "-", "where to load data from") - allowDeleteBody = flag.Bool("allow_delete_body", false, "unless set, HTTP DELETE methods may not have a body") - grpcAPIConfiguration = flag.String("grpc_api_configuration", "", "path to gRPC API Configuration in YAML format") - allowMerge = flag.Bool("allow_merge", false, "if set, generation one OpenAPI file out of multiple protos") - mergeFileName = flag.String("merge_file_name", "apidocs", "target OpenAPI file name prefix after merge") - useJSONNamesForFields = flag.Bool("json_names_for_fields", true, "if disabled, the original proto name will be used for generating OpenAPI definitions") - repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`.") - versionFlag = flag.Bool("version", false, "print the current version") - allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option") - includePackageInTags = flag.Bool("include_package_in_tags", false, "if unset, the gRPC service name is added to the `Tags` field of each operation. if set and the `package` directive is shown in the proto file, the package name will be prepended to the service name") - useFQNForOpenAPIName = flag.Bool("fqn_for_openapi_name", false, "if set, the object's OpenAPI names will use the fully qualify name from the proto definition (ie my.package.MyMessage.MyInnerMessage") - useGoTemplate = flag.Bool("use_go_templates", false, "if set, you can use Go templates in protofile comments") - disableDefaultErrors = flag.Bool("disable_default_errors", false, "if set, disables generation of default errors. This is useful if you have defined custom error handling") - enumsAsInts = flag.Bool("enums_as_ints", false, "whether to render enum values as integers, as opposed to string values") - simpleOperationIDs = flag.Bool("simple_operation_ids", false, "whether to remove the service prefix in the operationID generation. Can introduce duplicate operationIDs, use with caution.") - openAPIConfiguration = flag.String("openapi_configuration", "", "path to OpenAPI Configuration in YAML format") - generateUnboundMethods = flag.Bool("generate_unbound_methods", false, "generate swagger metadata even for RPC methods that have no HttpRule annotation") + importPrefix = flag.String("import_prefix", "", "prefix to be added to go package paths for imported proto files") + file = flag.String("file", "-", "where to load data from") + allowDeleteBody = flag.Bool("allow_delete_body", false, "unless set, HTTP DELETE methods may not have a body") + grpcAPIConfiguration = flag.String("grpc_api_configuration", "", "path to file which describes the gRPC API Configuration in YAML format") + allowMerge = flag.Bool("allow_merge", false, "if set, generation one OpenAPI file out of multiple protos") + mergeFileName = flag.String("merge_file_name", "apidocs", "target OpenAPI file name prefix after merge") + useJSONNamesForFields = flag.Bool("json_names_for_fields", true, "if disabled, the original proto name will be used for generating OpenAPI definitions") + repeatedPathParamSeparator = flag.String("repeated_path_param_separator", "csv", "configures how repeated fields should be split. Allowed values are `csv`, `pipes`, `ssv` and `tsv`") + versionFlag = flag.Bool("version", false, "print the current version") + allowRepeatedFieldsInBody = flag.Bool("allow_repeated_fields_in_body", false, "allows to use repeated field in `body` and `response_body` field of `google.api.http` annotation option") + includePackageInTags = flag.Bool("include_package_in_tags", false, "if unset, the gRPC service name is added to the `Tags` field of each operation. If set and the `package` directive is shown in the proto file, the package name will be prepended to the service name") + useFQNForOpenAPIName = flag.Bool("fqn_for_openapi_name", false, "if set, the object's OpenAPI names will use the fully qualified names from the proto definition (ie my.package.MyMessage.MyInnerMessage). DEPRECATED: prefer `openapi_naming_strategy=fqn`") + openAPINamingStrategy = flag.String("openapi_naming_strategy", "", "use the given OpenAPI naming strategy. Allowed values are `legacy`, `fqn`, `simple`. If unset, either `legacy` or `fqn` are selected, depending on the value of the `fqn_for_openapi_name` flag") + useGoTemplate = flag.Bool("use_go_templates", false, "if set, you can use Go templates in protofile comments") + disableDefaultErrors = flag.Bool("disable_default_errors", false, "if set, disables generation of default errors. This is useful if you have defined custom error handling") + enumsAsInts = flag.Bool("enums_as_ints", false, "whether to render enum values as integers, as opposed to string values") + simpleOperationIDs = flag.Bool("simple_operation_ids", false, "whether to remove the service prefix in the operationID generation. Can introduce duplicate operationIDs, use with caution.") + proto3OptionalNullable = flag.Bool("proto3_optional_nullable", false, "whether Proto3 Optional fields should be marked as x-nullable") + openAPIConfiguration = flag.String("openapi_configuration", "", "path to file which describes the OpenAPI Configuration in YAML format") + generateUnboundMethods = flag.Bool("generate_unbound_methods", false, "generate swagger metadata even for RPC methods that have no HttpRule annotation") + recursiveDepth = flag.Int("recursive-depth", 1000, "maximum recursion count allowed for a field type") + omitEnumDefaultValue = flag.Bool("omit_enum_default_value", false, "if set, omit default enum value") + outputFormat = flag.String("output_format", string(genopenapi.FormatJSON), fmt.Sprintf("output content format. Allowed values are: `%s`, `%s`", genopenapi.FormatJSON, genopenapi.FormatYAML)) + visibilityRestrictionSelectors = utilities.StringArrayFlag(flag.CommandLine, "visibility_restriction_selectors", "list of `google.api.VisibilityRule` visibility labels to include in the generated output when a visibility annotation is defined. Repeat this option to supply multiple values. Elements without visibility annotations are unaffected by this setting.") ) // Variables set by goreleaser at build time @@ -86,12 +93,34 @@ func main() { reg.SetUseJSONNamesForFields(*useJSONNamesForFields) reg.SetAllowRepeatedFieldsInBody(*allowRepeatedFieldsInBody) reg.SetIncludePackageInTags(*includePackageInTags) + reg.SetUseFQNForOpenAPIName(*useFQNForOpenAPIName) + // Set the naming strategy either directly from the flag, or via the value of the legacy fqn_for_openapi_name + // flag. + namingStrategy := *openAPINamingStrategy + if *useFQNForOpenAPIName { + if namingStrategy != "" { + glog.Fatal("The deprecated `fqn_for_openapi_name` flag must remain unset if `openapi_naming_strategy` is set.") + } + glog.Warning("The `fqn_for_openapi_name` flag is deprecated. Please use `openapi_naming_strategy=fqn` instead.") + namingStrategy = "fqn" + } else if namingStrategy == "" { + namingStrategy = "legacy" + } + if strategyFn := genopenapi.LookupNamingStrategy(namingStrategy); strategyFn == nil { + emitError(fmt.Errorf("invalid naming strategy %q", namingStrategy)) + return + } + reg.SetOpenAPINamingStrategy(namingStrategy) reg.SetUseGoTemplate(*useGoTemplate) reg.SetEnumsAsInts(*enumsAsInts) reg.SetDisableDefaultErrors(*disableDefaultErrors) reg.SetSimpleOperationIDs(*simpleOperationIDs) + reg.SetProto3OptionalNullable(*proto3OptionalNullable) reg.SetGenerateUnboundMethods(*generateUnboundMethods) + reg.SetRecursiveDepth(*recursiveDepth) + reg.SetOmitEnumDefaultValue(*omitEnumDefaultValue) + reg.SetVisibilityRestrictionSelectors(*visibilityRestrictionSelectors) if err := reg.SetRepeatedPathParamSeparator(*repeatedPathParamSeparator); err != nil { emitError(err) return @@ -107,7 +136,13 @@ func main() { } } - g := genopenapi.New(reg) + format := genopenapi.Format(*outputFormat) + if err := format.Validate(); err != nil { + emitError(err) + return + } + + g := genopenapi.New(reg, format) if err := genopenapi.AddErrorDefs(reg); err != nil { emitError(err) @@ -149,7 +184,9 @@ func emitFiles(out []*descriptor.ResponseFile) { for idx, item := range out { files[idx] = item.CodeGeneratorResponse_File } - emitResp(&pluginpb.CodeGeneratorResponse{File: files}) + resp := &pluginpb.CodeGeneratorResponse{File: files} + codegenerator.SetSupportedFeaturesOnCodeGeneratorResponse(resp) + emitResp(resp) } func emitError(err error) { diff --git a/gateway/protoc-gen-openapiv2/main_test.go b/gateway/protoc-gen-openapiv2/main_test.go index 514840a..e1b9a1f 100644 --- a/gateway/protoc-gen-openapiv2/main_test.go +++ b/gateway/protoc-gen-openapiv2/main_test.go @@ -22,98 +22,175 @@ func TestParseReqParam(t *testing.T) { importPathV string mergeFileNameV string useFQNForOpenAPINameV bool + openAPINamingStrategyV string }{ { // this one must be first - with no leading clearFlags call it // verifies our expectation of default values as we reset by // clearFlags - name: "Test 0", - expected: map[string]string{}, - request: "", - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "-", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 0", + expected: map[string]string{}, + request: "", + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "-", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 1", - expected: map[string]string{"google/api/annotations.proto": "github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api"}, - request: "allow_delete_body,allow_merge,allow_repeated_fields_in_body,include_package_in_tags,file=./foo.pb,import_prefix=/bar/baz,Mgoogle/api/annotations.proto=github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api", - allowDeleteBodyV: true, allowMergeV: true, allowRepeatedFieldsInBodyV: true, includePackageInTagsV: true, - fileV: "./foo.pb", importPathV: "/bar/baz", mergeFileNameV: "apidocs", + name: "Test 1", + expected: map[string]string{"google/api/annotations.proto": "github.com/googleapis/googleapis/google/api"}, + request: "allow_delete_body,allow_merge,allow_repeated_fields_in_body,include_package_in_tags,file=./foo.pb,import_prefix=/bar/baz,Mgoogle/api/annotations.proto=github.com/googleapis/googleapis/google/api", + allowDeleteBodyV: true, + allowMergeV: true, + allowRepeatedFieldsInBodyV: true, + includePackageInTagsV: true, + fileV: "./foo.pb", + importPathV: "/bar/baz", + mergeFileNameV: "apidocs", }, { - name: "Test 2", - expected: map[string]string{"google/api/annotations.proto": "github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api"}, - request: "allow_delete_body=true,allow_merge=true,allow_repeated_fields_in_body=true,include_package_in_tags=true,merge_file_name=test_name,file=./foo.pb,import_prefix=/bar/baz,Mgoogle/api/annotations.proto=github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api", - allowDeleteBodyV: true, allowMergeV: true, allowRepeatedFieldsInBodyV: true, includePackageInTagsV: true, - fileV: "./foo.pb", importPathV: "/bar/baz", mergeFileNameV: "test_name", + name: "Test 2", + expected: map[string]string{"google/api/annotations.proto": "github.com/googleapis/googleapis/google/api"}, + request: "allow_delete_body=true,allow_merge=true,allow_repeated_fields_in_body=true,include_package_in_tags=true,merge_file_name=test_name,file=./foo.pb,import_prefix=/bar/baz,Mgoogle/api/annotations.proto=github.com/googleapis/googleapis/google/api", + allowDeleteBodyV: true, + allowMergeV: true, + allowRepeatedFieldsInBodyV: true, + includePackageInTagsV: true, + fileV: "./foo.pb", + importPathV: "/bar/baz", + mergeFileNameV: "test_name", }, { - name: "Test 3", - expected: map[string]string{"a/b/c.proto": "github.com/x/y/z", "f/g/h.proto": "github.com/1/2/3/"}, - request: "allow_delete_body=false,allow_merge=false,Ma/b/c.proto=github.com/x/y/z,Mf/g/h.proto=github.com/1/2/3/", - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 3", + expected: map[string]string{"a/b/c.proto": "github.com/x/y/z", "f/g/h.proto": "github.com/1/2/3/"}, + request: "allow_delete_body=false,allow_merge=false,Ma/b/c.proto=github.com/x/y/z,Mf/g/h.proto=github.com/1/2/3/", + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 4", - expected: map[string]string{}, - request: "", - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 4", + expected: map[string]string{}, + request: "", + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 5", - expected: map[string]string{}, - request: "unknown_param=17", - expectedError: errors.New("cannot set flag unknown_param=17: no such flag -unknown_param"), - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 5", + expected: map[string]string{}, + request: "unknown_param=17", + expectedError: errors.New("cannot set flag unknown_param=17: no such flag -unknown_param"), + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 6", - expected: map[string]string{}, - request: "Mfoo", - expectedError: errors.New("cannot set flag Mfoo: no such flag -Mfoo"), - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 6", + expected: map[string]string{}, + request: "Mfoo", + expectedError: errors.New("cannot set flag Mfoo: no such flag -Mfoo"), + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 7", - expected: map[string]string{}, - request: "allow_delete_body,file,import_prefix,allow_merge,allow_repeated_fields_in_body,include_package_in_tags,merge_file_name", - allowDeleteBodyV: true, allowMergeV: true, allowRepeatedFieldsInBodyV: true, includePackageInTagsV: true, - fileV: "", importPathV: "", mergeFileNameV: "", + name: "Test 7", + expected: map[string]string{}, + request: "allow_delete_body,file,import_prefix,allow_merge,allow_repeated_fields_in_body,include_package_in_tags,merge_file_name", + allowDeleteBodyV: true, + allowMergeV: true, + allowRepeatedFieldsInBodyV: true, + includePackageInTagsV: true, + fileV: "", + importPathV: "", + mergeFileNameV: "", }, { - name: "Test 8", - expected: map[string]string{}, - request: "allow_delete_body,file,import_prefix,allow_merge,allow_repeated_fields_in_body=3,merge_file_name", - expectedError: errors.New(`cannot set flag allow_repeated_fields_in_body=3: parse error`), - allowDeleteBodyV: true, allowMergeV: true, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 8", + expected: map[string]string{}, + request: "allow_delete_body,file,import_prefix,allow_merge,allow_repeated_fields_in_body=3,merge_file_name", + expectedError: errors.New(`cannot set flag allow_repeated_fields_in_body=3: parse error`), + allowDeleteBodyV: true, + allowMergeV: true, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 9", - expected: map[string]string{}, - request: "include_package_in_tags=3", - expectedError: errors.New(`cannot set flag include_package_in_tags=3: parse error`), - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 9", + expected: map[string]string{}, + request: "include_package_in_tags=3", + expectedError: errors.New(`cannot set flag include_package_in_tags=3: parse error`), + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 10", - expected: map[string]string{}, - request: "fqn_for_openapi_name=3", - expectedError: errors.New(`cannot set flag fqn_for_openapi_name=3: parse error`), - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, useFQNForOpenAPINameV: false, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 10", + expected: map[string]string{}, + request: "fqn_for_openapi_name=3", + expectedError: errors.New(`cannot set flag fqn_for_openapi_name=3: parse error`), + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + useFQNForOpenAPINameV: false, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, { - name: "Test 11", - expected: map[string]string{}, - request: "fqn_for_openapi_name=true", - allowDeleteBodyV: false, allowMergeV: false, allowRepeatedFieldsInBodyV: false, includePackageInTagsV: false, useFQNForOpenAPINameV: true, - fileV: "stdin", importPathV: "", mergeFileNameV: "apidocs", + name: "Test 11", + expected: map[string]string{}, + request: "fqn_for_openapi_name=true", + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + useFQNForOpenAPINameV: true, + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", + }, + { + name: "Test 12", + expected: map[string]string{}, + request: "openapi_naming_strategy=simple", + allowDeleteBodyV: false, + allowMergeV: false, + allowRepeatedFieldsInBodyV: false, + includePackageInTagsV: false, + useFQNForOpenAPINameV: false, + openAPINamingStrategyV: "simple", + fileV: "stdin", + importPathV: "", + mergeFileNameV: "apidocs", }, } @@ -140,15 +217,26 @@ func TestParseReqParam(t *testing.T) { tt.Errorf("expected error malformed, expected %q, got %q", tc.expectedError.Error(), err.Error()) } } - checkFlags(tc.allowDeleteBodyV, tc.allowMergeV, tc.allowRepeatedFieldsInBodyV, tc.includePackageInTagsV, tc.useFQNForOpenAPINameV, tc.fileV, tc.importPathV, tc.mergeFileNameV, tt, i) + checkFlags(tc.allowDeleteBodyV, tc.allowMergeV, tc.allowRepeatedFieldsInBodyV, tc.includePackageInTagsV, tc.useFQNForOpenAPINameV, tc.openAPINamingStrategyV, tc.fileV, tc.importPathV, tc.mergeFileNameV, tt, i) clearFlags() }) } - } -func checkFlags(allowDeleteV, allowMergeV, allowRepeatedFieldsInBodyV, includePackageInTagsV bool, useFQNForOpenAPINameV bool, fileV, importPathV, mergeFileNameV string, t *testing.T, tid int) { +func checkFlags( + allowDeleteV, + allowMergeV, + allowRepeatedFieldsInBodyV, + includePackageInTagsV bool, + useFQNForOpenAPINameV bool, + openAPINamingStrategyV, + fileV, + importPathV, + mergeFileNameV string, + t *testing.T, + tid int, +) { if *importPrefix != importPathV { t.Errorf("Test %v: import_prefix misparsed, expected '%v', got '%v'", tid, importPathV, *importPrefix) } @@ -173,6 +261,9 @@ func checkFlags(allowDeleteV, allowMergeV, allowRepeatedFieldsInBodyV, includePa if *useFQNForOpenAPIName != useFQNForOpenAPINameV { t.Errorf("Test %v: fqn_for_openapi_name misparsed, expected '%v', got '%v'", tid, useFQNForOpenAPINameV, *useFQNForOpenAPIName) } + if *openAPINamingStrategy != openAPINamingStrategyV { + t.Errorf("Test %v: openapi_naming_strategy misparsed, expected '%v', got '%v'", tid, openAPINamingStrategyV, *openAPINamingStrategy) + } } func clearFlags() { @@ -183,4 +274,6 @@ func clearFlags() { *allowRepeatedFieldsInBody = false *includePackageInTags = false *mergeFileName = "apidocs" + *useFQNForOpenAPIName = false + *openAPINamingStrategy = "" } diff --git a/gateway/protoc-gen-openapiv2/options/BUILD.bazel b/gateway/protoc-gen-openapiv2/options/BUILD.bazel index 21e9273..ecbca2b 100644 --- a/gateway/protoc-gen-openapiv2/options/BUILD.bazel +++ b/gateway/protoc-gen-openapiv2/options/BUILD.bazel @@ -13,7 +13,7 @@ filegroup( ) go_library( - name = "go_default_library", + name = "options", embed = [":options_go_proto"], importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options", ) @@ -36,3 +36,9 @@ go_proto_library( importpath = "github.com/binchencoder/ease-gateway/gateway/protoc-gen-openapiv2/options", proto = ":options_proto", ) + +alias( + name = "go_default_library", + actual = ":options", + visibility = ["//visibility:public"], +) diff --git a/gateway/protoc-gen-openapiv2/options/annotations.pb.go b/gateway/protoc-gen-openapiv2/options/annotations.pb.go old mode 100644 new mode 100755 index b8af0e1..7a0c232 --- a/gateway/protoc-gen-openapiv2/options/annotations.pb.go +++ b/gateway/protoc-gen-openapiv2/options/annotations.pb.go @@ -1,16 +1,15 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: gateway/protoc-gen-openapiv2/options/annotations.proto package options import ( - proto "github.com/golang/protobuf/proto" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" reflect "reflect" ) @@ -21,13 +20,9 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ { - ExtendedType: (*descriptor.FileOptions)(nil), + ExtendedType: (*descriptorpb.FileOptions)(nil), ExtensionType: (*Swagger)(nil), Field: 1042, Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger", @@ -35,7 +30,7 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []pro Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", }, { - ExtendedType: (*descriptor.MethodOptions)(nil), + ExtendedType: (*descriptorpb.MethodOptions)(nil), ExtensionType: (*Operation)(nil), Field: 1042, Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation", @@ -43,7 +38,7 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []pro Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", }, { - ExtendedType: (*descriptor.MessageOptions)(nil), + ExtendedType: (*descriptorpb.MessageOptions)(nil), ExtensionType: (*Schema)(nil), Field: 1042, Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema", @@ -51,7 +46,7 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []pro Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", }, { - ExtendedType: (*descriptor.ServiceOptions)(nil), + ExtendedType: (*descriptorpb.ServiceOptions)(nil), ExtensionType: (*Tag)(nil), Field: 1042, Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag", @@ -59,7 +54,7 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []pro Filename: "gateway/protoc-gen-openapiv2/options/annotations.proto", }, { - ExtendedType: (*descriptor.FieldOptions)(nil), + ExtendedType: (*descriptorpb.FieldOptions)(nil), ExtensionType: (*JSONSchema)(nil), Field: 1042, Name: "grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field", @@ -68,57 +63,32 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes = []pro }, } -// Extension fields to descriptor.FileOptions. +// Extension fields to descriptorpb.FileOptions. var ( - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. - // - // All IDs are the same, as assigned. It is okay that they are the same, as they extend - // different descriptor messages. - // // optional grpc.gateway.protoc_gen_openapiv2.options.Swagger openapiv2_swagger = 1042; E_Openapiv2Swagger = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[0] ) -// Extension fields to descriptor.MethodOptions. +// Extension fields to descriptorpb.MethodOptions. var ( - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. - // - // All IDs are the same, as assigned. It is okay that they are the same, as they extend - // different descriptor messages. - // // optional grpc.gateway.protoc_gen_openapiv2.options.Operation openapiv2_operation = 1042; E_Openapiv2Operation = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[1] ) -// Extension fields to descriptor.MessageOptions. +// Extension fields to descriptorpb.MessageOptions. var ( - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. - // - // All IDs are the same, as assigned. It is okay that they are the same, as they extend - // different descriptor messages. - // // optional grpc.gateway.protoc_gen_openapiv2.options.Schema openapiv2_schema = 1042; E_Openapiv2Schema = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[2] ) -// Extension fields to descriptor.ServiceOptions. +// Extension fields to descriptorpb.ServiceOptions. var ( - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. - // - // All IDs are the same, as assigned. It is okay that they are the same, as they extend - // different descriptor messages. - // // optional grpc.gateway.protoc_gen_openapiv2.options.Tag openapiv2_tag = 1042; E_Openapiv2Tag = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[3] ) -// Extension fields to descriptor.FieldOptions. +// Extension fields to descriptorpb.FieldOptions. var ( - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. - // - // All IDs are the same, as assigned. It is okay that they are the same, as they extend - // different descriptor messages. - // // optional grpc.gateway.protoc_gen_openapiv2.options.JSONSchema openapiv2_field = 1042; E_Openapiv2Field = &file_gateway_protoc_gen_openapiv2_options_annotations_proto_extTypes[4] ) @@ -186,16 +156,16 @@ var file_gateway_protoc_gen_openapiv2_options_annotations_proto_rawDesc = []byte } var file_gateway_protoc_gen_openapiv2_options_annotations_proto_goTypes = []interface{}{ - (*descriptor.FileOptions)(nil), // 0: google.protobuf.FileOptions - (*descriptor.MethodOptions)(nil), // 1: google.protobuf.MethodOptions - (*descriptor.MessageOptions)(nil), // 2: google.protobuf.MessageOptions - (*descriptor.ServiceOptions)(nil), // 3: google.protobuf.ServiceOptions - (*descriptor.FieldOptions)(nil), // 4: google.protobuf.FieldOptions - (*Swagger)(nil), // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger - (*Operation)(nil), // 6: grpc.gateway.protoc_gen_openapiv2.options.Operation - (*Schema)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Schema - (*Tag)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Tag - (*JSONSchema)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + (*descriptorpb.FileOptions)(nil), // 0: google.protobuf.FileOptions + (*descriptorpb.MethodOptions)(nil), // 1: google.protobuf.MethodOptions + (*descriptorpb.MessageOptions)(nil), // 2: google.protobuf.MessageOptions + (*descriptorpb.ServiceOptions)(nil), // 3: google.protobuf.ServiceOptions + (*descriptorpb.FieldOptions)(nil), // 4: google.protobuf.FieldOptions + (*Swagger)(nil), // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger + (*Operation)(nil), // 6: grpc.gateway.protoc_gen_openapiv2.options.Operation + (*Schema)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Schema + (*Tag)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Tag + (*JSONSchema)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema } var file_gateway_protoc_gen_openapiv2_options_annotations_proto_depIdxs = []int32{ 0, // 0: grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger:extendee -> google.protobuf.FileOptions diff --git a/gateway/protoc-gen-openapiv2/options/annotations.proto b/gateway/protoc-gen-openapiv2/options/annotations.proto index ad054db..63dc872 100644 --- a/gateway/protoc-gen-openapiv2/options/annotations.proto +++ b/gateway/protoc-gen-openapiv2/options/annotations.proto @@ -8,35 +8,35 @@ import "google/protobuf/descriptor.proto"; import "gateway/protoc-gen-openapiv2/options/openapiv2.proto"; extend google.protobuf.FileOptions { - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Swagger openapiv2_swagger = 1042; } extend google.protobuf.MethodOptions { - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Operation openapiv2_operation = 1042; } extend google.protobuf.MessageOptions { - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Schema openapiv2_schema = 1042; } extend google.protobuf.ServiceOptions { - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Tag openapiv2_tag = 1042; } extend google.protobuf.FieldOptions { - // ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project. + // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. diff --git a/gateway/protoc-gen-openapiv2/options/openapiv2.pb.go b/gateway/protoc-gen-openapiv2/options/openapiv2.pb.go old mode 100644 new mode 100755 index b8e1322..fceae2e --- a/gateway/protoc-gen-openapiv2/options/openapiv2.pb.go +++ b/gateway/protoc-gen-openapiv2/options/openapiv2.pb.go @@ -1,16 +1,15 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: gateway/protoc-gen-openapiv2/options/openapiv2.proto package options import ( - proto "github.com/golang/protobuf/proto" - _struct "github.com/golang/protobuf/ptypes/struct" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" reflect "reflect" sync "sync" ) @@ -22,12 +21,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -// Scheme describes the schemes supported by the OpenAPI Swagger -// and Operation objects. type Scheme int32 const ( @@ -144,11 +137,9 @@ func (x JSONSchema_JSONSchemaSimpleTypes) Number() protoreflect.EnumNumber { // Deprecated: Use JSONSchema_JSONSchemaSimpleTypes.Descriptor instead. func (JSONSchema_JSONSchemaSimpleTypes) EnumDescriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{8, 0} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{9, 0} } -// The type of the security scheme. Valid values are "basic", -// "apiKey" or "oauth2". type SecurityScheme_Type int32 const ( @@ -198,10 +189,9 @@ func (x SecurityScheme_Type) Number() protoreflect.EnumNumber { // Deprecated: Use SecurityScheme_Type.Descriptor instead. func (SecurityScheme_Type) EnumDescriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11, 0} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 0} } -// The location of the API key. Valid values are "query" or "header". type SecurityScheme_In int32 const ( @@ -248,11 +238,9 @@ func (x SecurityScheme_In) Number() protoreflect.EnumNumber { // Deprecated: Use SecurityScheme_In.Descriptor instead. func (SecurityScheme_In) EnumDescriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11, 1} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 1} } -// The flow used by the OAuth2 security scheme. Valid values are -// "implicit", "password", "application" or "accessCode". type SecurityScheme_Flow int32 const ( @@ -305,87 +293,26 @@ func (x SecurityScheme_Flow) Number() protoreflect.EnumNumber { // Deprecated: Use SecurityScheme_Flow.Descriptor instead. func (SecurityScheme_Flow) EnumDescriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11, 2} -} - -// `Swagger` is a representation of OpenAPI v2 specification's Swagger object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject -// -// Example: -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { -// info: { -// title: "Echo API"; -// version: "1.0"; -// description: "; -// contact: { -// name: "gRPC-Gateway project"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway"; -// email: "none@example.com"; -// }; -// license: { -// name: "BSD 3-Clause License"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; -// }; -// }; -// schemes: HTTPS; -// consumes: "application/json"; -// produces: "application/json"; -// }; -// + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 2} +} + type Swagger struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Specifies the OpenAPI Specification version being used. It can be - // used by the OpenAPI UI and other clients to interpret the API listing. The - // value MUST be "2.0". - Swagger string `protobuf:"bytes,1,opt,name=swagger,proto3" json:"swagger,omitempty"` - // Provides metadata about the API. The metadata can be used by the - // clients if needed. - Info *Info `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` - // The host (name or ip) serving the API. This MUST be the host only and does - // not include the scheme nor sub-paths. It MAY include a port. If the host is - // not included, the host serving the documentation is to be used (including - // the port). The host does not support path templating. - Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` - // The base path on which the API is served, which is relative to the host. If - // it is not included, the API is served directly under the host. The value - // MUST start with a leading slash (/). The basePath does not support path - // templating. - // Note that using `base_path` does not change the endpoint paths that are - // generated in the resulting OpenAPI file. If you wish to use `base_path` - // with relatively generated OpenAPI paths, the `base_path` prefix must be - // manually removed from your `google.api.http` paths and your code changed to - // serve the API from the `base_path`. - BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"` - // The transfer protocol of the API. Values MUST be from the list: "http", - // "https", "ws", "wss". If the schemes is not included, the default scheme to - // be used is the one used to access the OpenAPI definition itself. - Schemes []Scheme `protobuf:"varint,5,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` - // A list of MIME types the APIs can consume. This is global to all APIs but - // can be overridden on specific API calls. Value MUST be as described under - // Mime Types. - Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` - // A list of MIME types the APIs can produce. This is global to all APIs but - // can be overridden on specific API calls. Value MUST be as described under - // Mime Types. - Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` - // An object to hold responses that can be used across operations. This - // property does not define global responses for all operations. - Responses map[string]*Response `protobuf:"bytes,10,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - // Security scheme definitions that can be used across the specification. - SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,11,opt,name=security_definitions,json=securityDefinitions,proto3" json:"security_definitions,omitempty"` - // A declaration of which security schemes are applied for the API as a whole. - // The list of values describes alternative security schemes that can be used - // (that is, there is a logical OR between the security requirements). - // Individual operations can override this definition. - Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` - // Additional external documentation. - ExternalDocs *ExternalDocumentation `protobuf:"bytes,14,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,15,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Swagger string `protobuf:"bytes,1,opt,name=swagger,proto3" json:"swagger,omitempty"` + Info *Info `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` + Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` + BasePath string `protobuf:"bytes,4,opt,name=base_path,json=basePath,proto3" json:"base_path,omitempty"` + Schemes []Scheme `protobuf:"varint,5,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` + Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` + Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` + Responses map[string]*Response `protobuf:"bytes,10,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + SecurityDefinitions *SecurityDefinitions `protobuf:"bytes,11,opt,name=security_definitions,json=securityDefinitions,proto3" json:"security_definitions,omitempty"` + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` + ExternalDocs *ExternalDocumentation `protobuf:"bytes,14,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + Extensions map[string]*structpb.Value `protobuf:"bytes,15,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Swagger) Reset() { @@ -497,84 +424,30 @@ func (x *Swagger) GetExternalDocs() *ExternalDocumentation { return nil } -func (x *Swagger) GetExtensions() map[string]*_struct.Value { +func (x *Swagger) GetExtensions() map[string]*structpb.Value { if x != nil { return x.Extensions } return nil } -// `Operation` is a representation of OpenAPI v2 specification's Operation object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject -// -// Example: -// -// service EchoService { -// rpc Echo(SimpleMessage) returns (SimpleMessage) { -// option (google.api.http) = { -// get: "/v1/example/echo/{id}" -// }; -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { -// summary: "Get a message."; -// operation_id: "getMessage"; -// tags: "echo"; -// responses: { -// key: "200" -// value: { -// description: "OK"; -// } -// } -// }; -// } -// } type Operation struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // A list of tags for API documentation control. Tags can be used for logical - // grouping of operations by resources or any other qualifier. - Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"` - // A short summary of what the operation does. For maximum readability in the - // swagger-ui, this field SHOULD be less than 120 characters. - Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` - // A verbose explanation of the operation behavior. GFM syntax can be used for - // rich text representation. - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - // Additional external documentation for this operation. - ExternalDocs *ExternalDocumentation `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - // Unique string used to identify the operation. The id MUST be unique among - // all operations described in the API. Tools and libraries MAY use the - // operationId to uniquely identify an operation, therefore, it is recommended - // to follow common programming naming conventions. - OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"` - // A list of MIME types the operation can consume. This overrides the consumes - // definition at the OpenAPI Object. An empty value MAY be used to clear the - // global definition. Value MUST be as described under Mime Types. - Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` - // A list of MIME types the operation can produce. This overrides the produces - // definition at the OpenAPI Object. An empty value MAY be used to clear the - // global definition. Value MUST be as described under Mime Types. - Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` - // The list of possible responses as they are returned from executing this - // operation. - Responses map[string]*Response `protobuf:"bytes,9,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - // The transfer protocol for the operation. Values MUST be from the list: - // "http", "https", "ws", "wss". The value overrides the OpenAPI Object - // schemes definition. - Schemes []Scheme `protobuf:"varint,10,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` - // Declares this operation to be deprecated. Usage of the declared operation - // should be refrained. Default value is false. - Deprecated bool `protobuf:"varint,11,opt,name=deprecated,proto3" json:"deprecated,omitempty"` - // A declaration of which security schemes are applied for this operation. The - // list of values describes alternative security schemes that can be used - // (that is, there is a logical OR between the security requirements). This - // definition overrides any declared top-level security. To remove a top-level - // security declaration, an empty array can be used. - Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,13,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"` + Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + ExternalDocs *ExternalDocumentation `protobuf:"bytes,4,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + OperationId string `protobuf:"bytes,5,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"` + Consumes []string `protobuf:"bytes,6,rep,name=consumes,proto3" json:"consumes,omitempty"` + Produces []string `protobuf:"bytes,7,rep,name=produces,proto3" json:"produces,omitempty"` + Responses map[string]*Response `protobuf:"bytes,9,rep,name=responses,proto3" json:"responses,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Schemes []Scheme `protobuf:"varint,10,rep,packed,name=schemes,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.Scheme" json:"schemes,omitempty"` + Deprecated bool `protobuf:"varint,11,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + Security []*SecurityRequirement `protobuf:"bytes,12,rep,name=security,proto3" json:"security,omitempty"` + Extensions map[string]*structpb.Value `protobuf:"bytes,13,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Operation) Reset() { @@ -686,38 +559,108 @@ func (x *Operation) GetSecurity() []*SecurityRequirement { return nil } -func (x *Operation) GetExtensions() map[string]*_struct.Value { +func (x *Operation) GetExtensions() map[string]*structpb.Value { if x != nil { return x.Extensions } return nil } -// `Response` is a representation of OpenAPI v2 specification's Response object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject -// -type Response struct { +type Header struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // `Description` is a short description of the response. - // GFM syntax can be used for rich text representation. Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` - // `Schema` optionally defines the structure of the response. - // If `Schema` is not provided, it means there is no content to the response. - Schema *Schema `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` - // `Examples` gives per-mimetype response examples. - // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object - Examples map[string]string `protobuf:"bytes,4,rep,name=examples,proto3" json:"examples,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Extensions map[string]*_struct.Value `protobuf:"bytes,5,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + Format string `protobuf:"bytes,3,opt,name=format,proto3" json:"format,omitempty"` + Default string `protobuf:"bytes,6,opt,name=default,proto3" json:"default,omitempty"` + Pattern string `protobuf:"bytes,13,opt,name=pattern,proto3" json:"pattern,omitempty"` +} + +func (x *Header) Reset() { + *x = Header{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Header) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Header) ProtoMessage() {} + +func (x *Header) ProtoReflect() protoreflect.Message { + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + 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 Header.ProtoReflect.Descriptor instead. +func (*Header) Descriptor() ([]byte, []int) { + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{2} +} + +func (x *Header) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Header) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *Header) GetFormat() string { + if x != nil { + return x.Format + } + return "" +} + +func (x *Header) GetDefault() string { + if x != nil { + return x.Default + } + return "" +} + +func (x *Header) GetPattern() string { + if x != nil { + return x.Pattern + } + return "" +} + +type Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + Schema *Schema `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` + Headers map[string]*Header `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Examples map[string]string `protobuf:"bytes,4,rep,name=examples,proto3" json:"examples,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Extensions map[string]*structpb.Value `protobuf:"bytes,5,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Response) Reset() { *x = Response{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -730,7 +673,7 @@ func (x *Response) String() string { func (*Response) ProtoMessage() {} func (x *Response) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -743,7 +686,7 @@ func (x *Response) ProtoReflect() protoreflect.Message { // Deprecated: Use Response.ProtoReflect.Descriptor instead. func (*Response) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{2} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{3} } func (x *Response) GetDescription() string { @@ -760,6 +703,13 @@ func (x *Response) GetSchema() *Schema { return nil } +func (x *Response) GetHeaders() map[string]*Header { + if x != nil { + return x.Headers + } + return nil +} + func (x *Response) GetExamples() map[string]string { if x != nil { return x.Examples @@ -767,63 +717,31 @@ func (x *Response) GetExamples() map[string]string { return nil } -func (x *Response) GetExtensions() map[string]*_struct.Value { +func (x *Response) GetExtensions() map[string]*structpb.Value { if x != nil { return x.Extensions } return nil } -// `Info` is a representation of OpenAPI v2 specification's Info object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject -// -// Example: -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { -// info: { -// title: "Echo API"; -// version: "1.0"; -// description: "; -// contact: { -// name: "gRPC-Gateway project"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway"; -// email: "none@example.com"; -// }; -// license: { -// name: "BSD 3-Clause License"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; -// }; -// }; -// ... -// }; -// type Info struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The title of the application. - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` - // A short description of the application. GFM syntax can be used for rich - // text representation. - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // The Terms of Service for the API. - TermsOfService string `protobuf:"bytes,3,opt,name=terms_of_service,json=termsOfService,proto3" json:"terms_of_service,omitempty"` - // The contact information for the exposed API. - Contact *Contact `protobuf:"bytes,4,opt,name=contact,proto3" json:"contact,omitempty"` - // The license information for the exposed API. - License *License `protobuf:"bytes,5,opt,name=license,proto3" json:"license,omitempty"` - // Provides the version of the application API (not to be confused - // with the specification version). - Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,7,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + TermsOfService string `protobuf:"bytes,3,opt,name=terms_of_service,json=termsOfService,proto3" json:"terms_of_service,omitempty"` + Contact *Contact `protobuf:"bytes,4,opt,name=contact,proto3" json:"contact,omitempty"` + License *License `protobuf:"bytes,5,opt,name=license,proto3" json:"license,omitempty"` + Version string `protobuf:"bytes,6,opt,name=version,proto3" json:"version,omitempty"` + Extensions map[string]*structpb.Value `protobuf:"bytes,7,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Info) Reset() { *x = Info{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -836,7 +754,7 @@ func (x *Info) String() string { func (*Info) ProtoMessage() {} func (x *Info) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -849,7 +767,7 @@ func (x *Info) ProtoReflect() protoreflect.Message { // Deprecated: Use Info.ProtoReflect.Descriptor instead. func (*Info) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{3} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{4} } func (x *Info) GetTitle() string { @@ -894,51 +812,27 @@ func (x *Info) GetVersion() string { return "" } -func (x *Info) GetExtensions() map[string]*_struct.Value { +func (x *Info) GetExtensions() map[string]*structpb.Value { if x != nil { return x.Extensions } return nil } -// `Contact` is a representation of OpenAPI v2 specification's Contact object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject -// -// Example: -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { -// info: { -// ... -// contact: { -// name: "gRPC-Gateway project"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway"; -// email: "none@example.com"; -// }; -// ... -// }; -// ... -// }; -// type Contact struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The identifying name of the contact person/organization. - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // The URL pointing to the contact information. MUST be in the format of a - // URL. - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` - // The email address of the contact person/organization. MUST be in the format - // of an email address. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` } func (x *Contact) Reset() { *x = Contact{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -951,7 +845,7 @@ func (x *Contact) String() string { func (*Contact) ProtoMessage() {} func (x *Contact) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -964,7 +858,7 @@ func (x *Contact) ProtoReflect() protoreflect.Message { // Deprecated: Use Contact.ProtoReflect.Descriptor instead. func (*Contact) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{4} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{5} } func (x *Contact) GetName() string { @@ -988,39 +882,19 @@ func (x *Contact) GetEmail() string { return "" } -// `License` is a representation of OpenAPI v2 specification's License object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject -// -// Example: -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { -// info: { -// ... -// license: { -// name: "BSD 3-Clause License"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; -// }; -// ... -// }; -// ... -// }; -// type License struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The license name used for the API. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // A URL to the license used for the API. MUST be in the format of a URL. - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` } func (x *License) Reset() { *x = License{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1033,7 +907,7 @@ func (x *License) String() string { func (*License) ProtoMessage() {} func (x *License) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1046,7 +920,7 @@ func (x *License) ProtoReflect() protoreflect.Message { // Deprecated: Use License.ProtoReflect.Descriptor instead. func (*License) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{5} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{6} } func (x *License) GetName() string { @@ -1063,39 +937,19 @@ func (x *License) GetUrl() string { return "" } -// `ExternalDocumentation` is a representation of OpenAPI v2 specification's -// ExternalDocumentation object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject -// -// Example: -// -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { -// ... -// external_docs: { -// description: "More about gRPC-Gateway"; -// url: "https://github.com/grpc-ecosystem/grpc-gateway"; -// } -// ... -// }; -// type ExternalDocumentation struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // A short description of the target documentation. GFM syntax can be used for - // rich text representation. Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` - // The URL for the target documentation. Value MUST be in the format - // of a URL. - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` } func (x *ExternalDocumentation) Reset() { *x = ExternalDocumentation{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1108,7 +962,7 @@ func (x *ExternalDocumentation) String() string { func (*ExternalDocumentation) ProtoMessage() {} func (x *ExternalDocumentation) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1121,7 +975,7 @@ func (x *ExternalDocumentation) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalDocumentation.ProtoReflect.Descriptor instead. func (*ExternalDocumentation) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{6} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{7} } func (x *ExternalDocumentation) GetDescription() string { @@ -1138,39 +992,22 @@ func (x *ExternalDocumentation) GetUrl() string { return "" } -// `Schema` is a representation of OpenAPI v2 specification's Schema object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject -// type Schema struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - JsonSchema *JSONSchema `protobuf:"bytes,1,opt,name=json_schema,json=jsonSchema,proto3" json:"json_schema,omitempty"` - // Adds support for polymorphism. The discriminator is the schema property - // name that is used to differentiate between other schema that inherit this - // schema. The property name used MUST be defined at this schema and it MUST - // be in the required property list. When used, the value MUST be the name of - // this schema or any schema that inherits it. - Discriminator string `protobuf:"bytes,2,opt,name=discriminator,proto3" json:"discriminator,omitempty"` - // Relevant only for Schema "properties" definitions. Declares the property as - // "read only". This means that it MAY be sent as part of a response but MUST - // NOT be sent as part of the request. Properties marked as readOnly being - // true SHOULD NOT be in the required list of the defined schema. Default - // value is false. - ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` - // Additional external documentation for this schema. - ExternalDocs *ExternalDocumentation `protobuf:"bytes,5,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` - // A free-form property to include an example of an instance for this schema in JSON. - // This is copied verbatim to the output. - Example string `protobuf:"bytes,6,opt,name=example,proto3" json:"example,omitempty"` + JsonSchema *JSONSchema `protobuf:"bytes,1,opt,name=json_schema,json=jsonSchema,proto3" json:"json_schema,omitempty"` + Discriminator string `protobuf:"bytes,2,opt,name=discriminator,proto3" json:"discriminator,omitempty"` + ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + ExternalDocs *ExternalDocumentation `protobuf:"bytes,5,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` + Example string `protobuf:"bytes,6,opt,name=example,proto3" json:"example,omitempty"` } func (x *Schema) Reset() { *x = Schema{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1183,7 +1020,7 @@ func (x *Schema) String() string { func (*Schema) ProtoMessage() {} func (x *Schema) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1196,7 +1033,7 @@ func (x *Schema) ProtoReflect() protoreflect.Message { // Deprecated: Use Schema.ProtoReflect.Descriptor instead. func (*Schema) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{7} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{8} } func (x *Schema) GetJsonSchema() *JSONSchema { @@ -1234,79 +1071,41 @@ func (x *Schema) GetExample() string { return "" } -// `JSONSchema` represents properties from JSON Schema taken, and as used, in -// the OpenAPI v2 spec. -// -// This includes changes made by OpenAPI v2. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject -// -// See also: https://cswr.github.io/JsonSchema/spec/basic_types/, -// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json -// -// Example: -// -// message SimpleMessage { -// option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { -// json_schema: { -// title: "SimpleMessage" -// description: "A simple message." -// required: ["id"] -// } -// }; -// -// // Id represents the message identifier. -// string id = 1; [ -// (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { -// {description: "The unique identifier of the simple message." -// }]; -// } -// type JSONSchema struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Ref is used to define an external reference to include in the message. - // This could be a fully qualified proto message reference, and that type must - // be imported into the protofile. If no message is identified, the Ref will - // be used verbatim in the output. - // For example: - // `ref: ".google.protobuf.Timestamp"`. - Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"` - // The title of the schema. - Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"` - // A short description of the schema. - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - Default string `protobuf:"bytes,7,opt,name=default,proto3" json:"default,omitempty"` - ReadOnly bool `protobuf:"varint,8,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` - MultipleOf float64 `protobuf:"fixed64,10,opt,name=multiple_of,json=multipleOf,proto3" json:"multiple_of,omitempty"` - // Maximum represents an inclusive upper limit for a numeric instance. The - // value of MUST be a number, - Maximum float64 `protobuf:"fixed64,11,opt,name=maximum,proto3" json:"maximum,omitempty"` - ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum,proto3" json:"exclusive_maximum,omitempty"` - // minimum represents an inclusive lower limit for a numeric instance. The - // value of MUST be a number, - Minimum float64 `protobuf:"fixed64,13,opt,name=minimum,proto3" json:"minimum,omitempty"` - ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum,proto3" json:"exclusive_minimum,omitempty"` - MaxLength uint64 `protobuf:"varint,15,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` - MinLength uint64 `protobuf:"varint,16,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` - Pattern string `protobuf:"bytes,17,opt,name=pattern,proto3" json:"pattern,omitempty"` - MaxItems uint64 `protobuf:"varint,20,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"` - MinItems uint64 `protobuf:"varint,21,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"` - UniqueItems bool `protobuf:"varint,22,opt,name=unique_items,json=uniqueItems,proto3" json:"unique_items,omitempty"` - MaxProperties uint64 `protobuf:"varint,24,opt,name=max_properties,json=maxProperties,proto3" json:"max_properties,omitempty"` - MinProperties uint64 `protobuf:"varint,25,opt,name=min_properties,json=minProperties,proto3" json:"min_properties,omitempty"` - Required []string `protobuf:"bytes,26,rep,name=required,proto3" json:"required,omitempty"` - // Items in 'array' must be unique. - Array []string `protobuf:"bytes,34,rep,name=array,proto3" json:"array,omitempty"` - Type []JSONSchema_JSONSchemaSimpleTypes `protobuf:"varint,35,rep,packed,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.JSONSchema_JSONSchemaSimpleTypes" json:"type,omitempty"` + Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"` + Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` + Default string `protobuf:"bytes,7,opt,name=default,proto3" json:"default,omitempty"` + ReadOnly bool `protobuf:"varint,8,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + Example string `protobuf:"bytes,9,opt,name=example,proto3" json:"example,omitempty"` + MultipleOf float64 `protobuf:"fixed64,10,opt,name=multiple_of,json=multipleOf,proto3" json:"multiple_of,omitempty"` + Maximum float64 `protobuf:"fixed64,11,opt,name=maximum,proto3" json:"maximum,omitempty"` + ExclusiveMaximum bool `protobuf:"varint,12,opt,name=exclusive_maximum,json=exclusiveMaximum,proto3" json:"exclusive_maximum,omitempty"` + Minimum float64 `protobuf:"fixed64,13,opt,name=minimum,proto3" json:"minimum,omitempty"` + ExclusiveMinimum bool `protobuf:"varint,14,opt,name=exclusive_minimum,json=exclusiveMinimum,proto3" json:"exclusive_minimum,omitempty"` + MaxLength uint64 `protobuf:"varint,15,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` + MinLength uint64 `protobuf:"varint,16,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` + Pattern string `protobuf:"bytes,17,opt,name=pattern,proto3" json:"pattern,omitempty"` + MaxItems uint64 `protobuf:"varint,20,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"` + MinItems uint64 `protobuf:"varint,21,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"` + UniqueItems bool `protobuf:"varint,22,opt,name=unique_items,json=uniqueItems,proto3" json:"unique_items,omitempty"` + MaxProperties uint64 `protobuf:"varint,24,opt,name=max_properties,json=maxProperties,proto3" json:"max_properties,omitempty"` + MinProperties uint64 `protobuf:"varint,25,opt,name=min_properties,json=minProperties,proto3" json:"min_properties,omitempty"` + Required []string `protobuf:"bytes,26,rep,name=required,proto3" json:"required,omitempty"` + Array []string `protobuf:"bytes,34,rep,name=array,proto3" json:"array,omitempty"` + Type []JSONSchema_JSONSchemaSimpleTypes `protobuf:"varint,35,rep,packed,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.JSONSchema_JSONSchemaSimpleTypes" json:"type,omitempty"` + Format string `protobuf:"bytes,36,opt,name=format,proto3" json:"format,omitempty"` + Enum []string `protobuf:"bytes,46,rep,name=enum,proto3" json:"enum,omitempty"` } func (x *JSONSchema) Reset() { *x = JSONSchema{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1319,7 +1118,7 @@ func (x *JSONSchema) String() string { func (*JSONSchema) ProtoMessage() {} func (x *JSONSchema) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1332,7 +1131,7 @@ func (x *JSONSchema) ProtoReflect() protoreflect.Message { // Deprecated: Use JSONSchema.ProtoReflect.Descriptor instead. func (*JSONSchema) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{8} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{9} } func (x *JSONSchema) GetRef() string { @@ -1370,6 +1169,13 @@ func (x *JSONSchema) GetReadOnly() bool { return false } +func (x *JSONSchema) GetExample() string { + if x != nil { + return x.Example + } + return "" +} + func (x *JSONSchema) GetMultipleOf() float64 { if x != nil { return x.MultipleOf @@ -1482,26 +1288,33 @@ func (x *JSONSchema) GetType() []JSONSchema_JSONSchemaSimpleTypes { return nil } -// `Tag` is a representation of OpenAPI v2 specification's Tag object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject -// +func (x *JSONSchema) GetFormat() string { + if x != nil { + return x.Format + } + return "" +} + +func (x *JSONSchema) GetEnum() []string { + if x != nil { + return x.Enum + } + return nil +} + type Tag struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // A short description for the tag. GFM syntax can be used for rich text - // representation. - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // Additional external documentation for this tag. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` ExternalDocs *ExternalDocumentation `protobuf:"bytes,3,opt,name=external_docs,json=externalDocs,proto3" json:"external_docs,omitempty"` } func (x *Tag) Reset() { *x = Tag{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1514,7 +1327,7 @@ func (x *Tag) String() string { func (*Tag) ProtoMessage() {} func (x *Tag) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1527,7 +1340,7 @@ func (x *Tag) ProtoReflect() protoreflect.Message { // Deprecated: Use Tag.ProtoReflect.Descriptor instead. func (*Tag) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{9} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{10} } func (x *Tag) GetDescription() string { @@ -1544,28 +1357,18 @@ func (x *Tag) GetExternalDocs() *ExternalDocumentation { return nil } -// `SecurityDefinitions` is a representation of OpenAPI v2 specification's -// Security Definitions object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject -// -// A declaration of the security schemes available to be used in the -// specification. This does not enforce the security schemes on the operations -// and only serves to provide the relevant details for each scheme. type SecurityDefinitions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // A single security scheme definition, mapping a "name" to the scheme it - // defines. Security map[string]*SecurityScheme `protobuf:"bytes,1,rep,name=security,proto3" json:"security,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *SecurityDefinitions) Reset() { *x = SecurityDefinitions{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1578,7 +1381,7 @@ func (x *SecurityDefinitions) String() string { func (*SecurityDefinitions) ProtoMessage() {} func (x *SecurityDefinitions) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1591,7 +1394,7 @@ func (x *SecurityDefinitions) ProtoReflect() protoreflect.Message { // Deprecated: Use SecurityDefinitions.ProtoReflect.Descriptor instead. func (*SecurityDefinitions) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{10} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11} } func (x *SecurityDefinitions) GetSecurity() map[string]*SecurityScheme { @@ -1601,54 +1404,26 @@ func (x *SecurityDefinitions) GetSecurity() map[string]*SecurityScheme { return nil } -// `SecurityScheme` is a representation of OpenAPI v2 specification's -// Security Scheme object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject -// -// Allows the definition of a security scheme that can be used by the -// operations. Supported schemes are basic authentication, an API key (either as -// a header or as a query parameter) and OAuth2's common flows (implicit, -// password, application and access code). type SecurityScheme struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The type of the security scheme. Valid values are "basic", - // "apiKey" or "oauth2". - Type SecurityScheme_Type `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Type" json:"type,omitempty"` - // A short description for security scheme. - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // The name of the header or query parameter to be used. - // Valid for apiKey. - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - // The location of the API key. Valid values are "query" or - // "header". - // Valid for apiKey. - In SecurityScheme_In `protobuf:"varint,4,opt,name=in,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_In" json:"in,omitempty"` - // The flow used by the OAuth2 security scheme. Valid values are - // "implicit", "password", "application" or "accessCode". - // Valid for oauth2. - Flow SecurityScheme_Flow `protobuf:"varint,5,opt,name=flow,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Flow" json:"flow,omitempty"` - // The authorization URL to be used for this flow. This SHOULD be in - // the form of a URL. - // Valid for oauth2/implicit and oauth2/accessCode. - AuthorizationUrl string `protobuf:"bytes,6,opt,name=authorization_url,json=authorizationUrl,proto3" json:"authorization_url,omitempty"` - // The token URL to be used for this flow. This SHOULD be in the - // form of a URL. - // Valid for oauth2/password, oauth2/application and oauth2/accessCode. - TokenUrl string `protobuf:"bytes,7,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"` - // The available scopes for the OAuth2 security scheme. - // Valid for oauth2. - Scopes *Scopes `protobuf:"bytes,8,opt,name=scopes,proto3" json:"scopes,omitempty"` - Extensions map[string]*_struct.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Type SecurityScheme_Type `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Type" json:"type,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + In SecurityScheme_In `protobuf:"varint,4,opt,name=in,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_In" json:"in,omitempty"` + Flow SecurityScheme_Flow `protobuf:"varint,5,opt,name=flow,proto3,enum=grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme_Flow" json:"flow,omitempty"` + AuthorizationUrl string `protobuf:"bytes,6,opt,name=authorization_url,json=authorizationUrl,proto3" json:"authorization_url,omitempty"` + TokenUrl string `protobuf:"bytes,7,opt,name=token_url,json=tokenUrl,proto3" json:"token_url,omitempty"` + Scopes *Scopes `protobuf:"bytes,8,opt,name=scopes,proto3" json:"scopes,omitempty"` + Extensions map[string]*structpb.Value `protobuf:"bytes,9,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *SecurityScheme) Reset() { *x = SecurityScheme{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1661,7 +1436,7 @@ func (x *SecurityScheme) String() string { func (*SecurityScheme) ProtoMessage() {} func (x *SecurityScheme) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1674,7 +1449,7 @@ func (x *SecurityScheme) ProtoReflect() protoreflect.Message { // Deprecated: Use SecurityScheme.ProtoReflect.Descriptor instead. func (*SecurityScheme) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{11} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12} } func (x *SecurityScheme) GetType() SecurityScheme_Type { @@ -1733,40 +1508,25 @@ func (x *SecurityScheme) GetScopes() *Scopes { return nil } -func (x *SecurityScheme) GetExtensions() map[string]*_struct.Value { +func (x *SecurityScheme) GetExtensions() map[string]*structpb.Value { if x != nil { return x.Extensions } return nil } -// `SecurityRequirement` is a representation of OpenAPI v2 specification's -// Security Requirement object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject -// -// Lists the required security schemes to execute this operation. The object can -// have multiple security schemes declared in it which are all required (that -// is, there is a logical AND between the schemes). -// -// The name used for each property MUST correspond to a security scheme -// declared in the Security Definitions. type SecurityRequirement struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Each name must correspond to a security scheme which is declared in - // the Security Definitions. If the security scheme is of type "oauth2", - // then the value is a list of scope names required for the execution. - // For other security scheme types, the array MUST be empty. SecurityRequirement map[string]*SecurityRequirement_SecurityRequirementValue `protobuf:"bytes,1,rep,name=security_requirement,json=securityRequirement,proto3" json:"security_requirement,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *SecurityRequirement) Reset() { *x = SecurityRequirement{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1779,7 +1539,7 @@ func (x *SecurityRequirement) String() string { func (*SecurityRequirement) ProtoMessage() {} func (x *SecurityRequirement) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1792,7 +1552,7 @@ func (x *SecurityRequirement) ProtoReflect() protoreflect.Message { // Deprecated: Use SecurityRequirement.ProtoReflect.Descriptor instead. func (*SecurityRequirement) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{13} } func (x *SecurityRequirement) GetSecurityRequirement() map[string]*SecurityRequirement_SecurityRequirementValue { @@ -1802,25 +1562,18 @@ func (x *SecurityRequirement) GetSecurityRequirement() map[string]*SecurityRequi return nil } -// `Scopes` is a representation of OpenAPI v2 specification's Scopes object. -// -// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject -// -// Lists the available scopes for an OAuth2 security scheme. type Scopes struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Maps between a name of a scope to a short description of it (as the value - // of the property). Scope map[string]string `protobuf:"bytes,1,rep,name=scope,proto3" json:"scope,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Scopes) Reset() { *x = Scopes{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1833,7 +1586,7 @@ func (x *Scopes) String() string { func (*Scopes) ProtoMessage() {} func (x *Scopes) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1846,7 +1599,7 @@ func (x *Scopes) ProtoReflect() protoreflect.Message { // Deprecated: Use Scopes.ProtoReflect.Descriptor instead. func (*Scopes) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{13} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{14} } func (x *Scopes) GetScope() map[string]string { @@ -1856,9 +1609,6 @@ func (x *Scopes) GetScope() map[string]string { return nil } -// If the security scheme is of type "oauth2", then the value is a list of -// scope names required for the execution. For other security scheme types, -// the array MUST be empty. type SecurityRequirement_SecurityRequirementValue struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1870,7 +1620,7 @@ type SecurityRequirement_SecurityRequirementValue struct { func (x *SecurityRequirement_SecurityRequirementValue) Reset() { *x = SecurityRequirement_SecurityRequirementValue{} if protoimpl.UnsafeEnabled { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[23] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1883,7 +1633,7 @@ func (x *SecurityRequirement_SecurityRequirementValue) String() string { func (*SecurityRequirement_SecurityRequirementValue) ProtoMessage() {} func (x *SecurityRequirement_SecurityRequirementValue) ProtoReflect() protoreflect.Message { - mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[23] + mi := &file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1896,7 +1646,7 @@ func (x *SecurityRequirement_SecurityRequirementValue) ProtoReflect() protorefle // Deprecated: Use SecurityRequirement_SecurityRequirementValue.ProtoReflect.Descriptor instead. func (*SecurityRequirement_SecurityRequirementValue) Descriptor() ([]byte, []int) { - return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{12, 0} + return file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP(), []int{13, 0} } func (x *SecurityRequirement_SecurityRequirementValue) GetScope() []string { @@ -2036,37 +1786,63 @@ var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0xd5, 0x03, 0x0a, 0x08, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, - 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, - 0x65, 0x6d, 0x61, 0x12, 0x5d, 0x0a, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, - 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x73, 0x12, 0x63, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, - 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, - 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, - 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, 0x45, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x73, 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, 0x55, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, - 0x04, 0x22, 0xd6, 0x03, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, + 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0xd8, 0x01, 0x0a, 0x06, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, + 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, + 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, + 0x4a, 0x04, 0x08, 0x0c, 0x10, 0x0d, 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x0f, 0x4a, 0x04, 0x08, 0x0f, + 0x10, 0x10, 0x4a, 0x04, 0x08, 0x10, 0x10, 0x11, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, 0x04, + 0x08, 0x12, 0x10, 0x13, 0x22, 0x9a, 0x05, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, + 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x5a, + 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x5d, 0x0a, 0x08, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x63, 0x0a, 0x0a, 0x65, 0x78, 0x74, + 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, + 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x6d, + 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x47, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, + 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3b, 0x0a, + 0x0d, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 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, 0x55, 0x0a, 0x0f, 0x45, 0x78, + 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0xd6, 0x03, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, @@ -2126,7 +1902,7 @@ var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x9f, 0x07, 0x0a, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0xdf, 0x07, 0x0a, 0x0a, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, @@ -2135,55 +1911,59 @@ var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc = []byte{ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x0b, - 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x0a, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x4f, 0x66, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, - 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, - 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x78, - 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x2b, - 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x69, - 0x6d, 0x75, 0x6d, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, - 0x73, 0x69, 0x76, 0x65, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, - 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x6d, 0x61, 0x78, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x69, - 0x6e, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x6d, 0x69, 0x6e, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, - 0x74, 0x65, 0x72, 0x6e, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, - 0x65, 0x72, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, - 0x18, 0x14, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73, - 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x15, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x21, 0x0a, - 0x0c, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x16, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, - 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, - 0x65, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x6f, - 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x70, - 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0d, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, - 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x72, - 0x72, 0x61, 0x79, 0x18, 0x22, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, - 0x12, 0x5f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x4b, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, - 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x22, 0x77, 0x0a, 0x15, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, - 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x52, 0x41, 0x59, - 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12, - 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, - 0x4e, 0x55, 0x4c, 0x4c, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, - 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x10, 0x06, 0x12, 0x0a, - 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, - 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x09, - 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x4a, 0x04, + 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, + 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x6d, 0x75, 0x6c, + 0x74, 0x69, 0x70, 0x6c, 0x65, 0x4f, 0x66, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, + 0x75, 0x6d, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, + 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, + 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, + 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x07, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x78, 0x63, 0x6c, + 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x4d, 0x69, + 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x61, 0x78, 0x4c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x69, 0x6e, 0x5f, 0x6c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6d, 0x69, 0x6e, 0x4c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x11, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x1b, 0x0a, + 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, + 0x6e, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, + 0x69, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x6e, 0x69, 0x71, 0x75, + 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, + 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, + 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x18, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, + 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, + 0x69, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, 0x69, 0x6e, 0x50, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, 0x22, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x05, 0x61, 0x72, 0x72, 0x61, 0x79, 0x12, 0x5f, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x4b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x5f, 0x67, + 0x65, 0x6e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, + 0x4a, 0x53, 0x4f, 0x4e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x24, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x6e, 0x75, 0x6d, 0x18, 0x2e, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x04, 0x65, 0x6e, 0x75, 0x6d, 0x22, 0x77, 0x0a, 0x15, 0x4a, 0x53, 0x4f, 0x4e, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, + 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, + 0x05, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x4f, 0x4f, 0x4c, + 0x45, 0x41, 0x4e, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x45, 0x52, + 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x55, 0x4c, 0x4c, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, + 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x42, 0x4a, 0x45, + 0x43, 0x54, 0x10, 0x06, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x07, + 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, + 0x10, 0x05, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x4a, 0x04, 0x08, 0x1b, 0x10, 0x1c, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, - 0x4a, 0x04, 0x08, 0x1d, 0x10, 0x1e, 0x4a, 0x04, 0x08, 0x1e, 0x10, 0x22, 0x4a, 0x04, 0x08, 0x24, + 0x4a, 0x04, 0x08, 0x1d, 0x10, 0x1e, 0x4a, 0x04, 0x08, 0x1e, 0x10, 0x22, 0x4a, 0x04, 0x08, 0x25, 0x10, 0x2a, 0x4a, 0x04, 0x08, 0x2a, 0x10, 0x2b, 0x4a, 0x04, 0x08, 0x2b, 0x10, 0x2e, 0x22, 0x94, 0x01, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, @@ -2324,7 +2104,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDescGZIP() []b } var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes = make([]protoimpl.MessageInfo, 26) +var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes = make([]protoimpl.MessageInfo, 28) var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_goTypes = []interface{}{ (Scheme)(0), // 0: grpc.gateway.protoc_gen_openapiv2.options.Scheme (JSONSchema_JSONSchemaSimpleTypes)(0), // 1: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.JSONSchemaSimpleTypes @@ -2333,77 +2113,81 @@ var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_goTypes = []interf (SecurityScheme_Flow)(0), // 4: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Flow (*Swagger)(nil), // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger (*Operation)(nil), // 6: grpc.gateway.protoc_gen_openapiv2.options.Operation - (*Response)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Response - (*Info)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Info - (*Contact)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.Contact - (*License)(nil), // 10: grpc.gateway.protoc_gen_openapiv2.options.License - (*ExternalDocumentation)(nil), // 11: grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation - (*Schema)(nil), // 12: grpc.gateway.protoc_gen_openapiv2.options.Schema - (*JSONSchema)(nil), // 13: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema - (*Tag)(nil), // 14: grpc.gateway.protoc_gen_openapiv2.options.Tag - (*SecurityDefinitions)(nil), // 15: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions - (*SecurityScheme)(nil), // 16: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme - (*SecurityRequirement)(nil), // 17: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement - (*Scopes)(nil), // 18: grpc.gateway.protoc_gen_openapiv2.options.Scopes - nil, // 19: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry - nil, // 20: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry - nil, // 21: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry - nil, // 22: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry - nil, // 23: grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry - nil, // 24: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry - nil, // 25: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry - nil, // 26: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry - nil, // 27: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry - (*SecurityRequirement_SecurityRequirementValue)(nil), // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue - nil, // 29: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry - nil, // 30: grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry - (*_struct.Value)(nil), // 31: google.protobuf.Value + (*Header)(nil), // 7: grpc.gateway.protoc_gen_openapiv2.options.Header + (*Response)(nil), // 8: grpc.gateway.protoc_gen_openapiv2.options.Response + (*Info)(nil), // 9: grpc.gateway.protoc_gen_openapiv2.options.Info + (*Contact)(nil), // 10: grpc.gateway.protoc_gen_openapiv2.options.Contact + (*License)(nil), // 11: grpc.gateway.protoc_gen_openapiv2.options.License + (*ExternalDocumentation)(nil), // 12: grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + (*Schema)(nil), // 13: grpc.gateway.protoc_gen_openapiv2.options.Schema + (*JSONSchema)(nil), // 14: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + (*Tag)(nil), // 15: grpc.gateway.protoc_gen_openapiv2.options.Tag + (*SecurityDefinitions)(nil), // 16: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions + (*SecurityScheme)(nil), // 17: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme + (*SecurityRequirement)(nil), // 18: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + (*Scopes)(nil), // 19: grpc.gateway.protoc_gen_openapiv2.options.Scopes + nil, // 20: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry + nil, // 21: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry + nil, // 22: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry + nil, // 23: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry + nil, // 24: grpc.gateway.protoc_gen_openapiv2.options.Response.HeadersEntry + nil, // 25: grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry + nil, // 26: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry + nil, // 27: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry + nil, // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry + nil, // 29: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry + (*SecurityRequirement_SecurityRequirementValue)(nil), // 30: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue + nil, // 31: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry + nil, // 32: grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry + (*structpb.Value)(nil), // 33: google.protobuf.Value } var file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_depIdxs = []int32{ - 8, // 0: grpc.gateway.protoc_gen_openapiv2.options.Swagger.info:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info + 9, // 0: grpc.gateway.protoc_gen_openapiv2.options.Swagger.info:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info 0, // 1: grpc.gateway.protoc_gen_openapiv2.options.Swagger.schemes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scheme - 19, // 2: grpc.gateway.protoc_gen_openapiv2.options.Swagger.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry - 15, // 3: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security_definitions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions - 17, // 4: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement - 11, // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation - 20, // 6: grpc.gateway.protoc_gen_openapiv2.options.Swagger.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry - 11, // 7: grpc.gateway.protoc_gen_openapiv2.options.Operation.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation - 21, // 8: grpc.gateway.protoc_gen_openapiv2.options.Operation.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry + 20, // 2: grpc.gateway.protoc_gen_openapiv2.options.Swagger.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry + 16, // 3: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security_definitions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions + 18, // 4: grpc.gateway.protoc_gen_openapiv2.options.Swagger.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + 12, // 5: grpc.gateway.protoc_gen_openapiv2.options.Swagger.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 21, // 6: grpc.gateway.protoc_gen_openapiv2.options.Swagger.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry + 12, // 7: grpc.gateway.protoc_gen_openapiv2.options.Operation.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 22, // 8: grpc.gateway.protoc_gen_openapiv2.options.Operation.responses:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry 0, // 9: grpc.gateway.protoc_gen_openapiv2.options.Operation.schemes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scheme - 17, // 10: grpc.gateway.protoc_gen_openapiv2.options.Operation.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement - 22, // 11: grpc.gateway.protoc_gen_openapiv2.options.Operation.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry - 12, // 12: grpc.gateway.protoc_gen_openapiv2.options.Response.schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Schema - 23, // 13: grpc.gateway.protoc_gen_openapiv2.options.Response.examples:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry - 24, // 14: grpc.gateway.protoc_gen_openapiv2.options.Response.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry - 9, // 15: grpc.gateway.protoc_gen_openapiv2.options.Info.contact:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Contact - 10, // 16: grpc.gateway.protoc_gen_openapiv2.options.Info.license:type_name -> grpc.gateway.protoc_gen_openapiv2.options.License - 25, // 17: grpc.gateway.protoc_gen_openapiv2.options.Info.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry - 13, // 18: grpc.gateway.protoc_gen_openapiv2.options.Schema.json_schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema - 11, // 19: grpc.gateway.protoc_gen_openapiv2.options.Schema.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation - 1, // 20: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.JSONSchemaSimpleTypes - 11, // 21: grpc.gateway.protoc_gen_openapiv2.options.Tag.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation - 26, // 22: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry - 2, // 23: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Type - 3, // 24: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.in:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.In - 4, // 25: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.flow:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Flow - 18, // 26: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.scopes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes - 27, // 27: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry - 29, // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.security_requirement:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry - 30, // 29: grpc.gateway.protoc_gen_openapiv2.options.Scopes.scope:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry - 7, // 30: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response - 31, // 31: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry.value:type_name -> google.protobuf.Value - 7, // 32: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response - 31, // 33: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry.value:type_name -> google.protobuf.Value - 31, // 34: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry.value:type_name -> google.protobuf.Value - 31, // 35: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry.value:type_name -> google.protobuf.Value - 16, // 36: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme - 31, // 37: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry.value:type_name -> google.protobuf.Value - 28, // 38: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue - 39, // [39:39] is the sub-list for method output_type - 39, // [39:39] is the sub-list for method input_type - 39, // [39:39] is the sub-list for extension type_name - 39, // [39:39] is the sub-list for extension extendee - 0, // [0:39] is the sub-list for field type_name + 18, // 10: grpc.gateway.protoc_gen_openapiv2.options.Operation.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement + 23, // 11: grpc.gateway.protoc_gen_openapiv2.options.Operation.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry + 13, // 12: grpc.gateway.protoc_gen_openapiv2.options.Response.schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Schema + 24, // 13: grpc.gateway.protoc_gen_openapiv2.options.Response.headers:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.HeadersEntry + 25, // 14: grpc.gateway.protoc_gen_openapiv2.options.Response.examples:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExamplesEntry + 26, // 15: grpc.gateway.protoc_gen_openapiv2.options.Response.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry + 10, // 16: grpc.gateway.protoc_gen_openapiv2.options.Info.contact:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Contact + 11, // 17: grpc.gateway.protoc_gen_openapiv2.options.Info.license:type_name -> grpc.gateway.protoc_gen_openapiv2.options.License + 27, // 18: grpc.gateway.protoc_gen_openapiv2.options.Info.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry + 14, // 19: grpc.gateway.protoc_gen_openapiv2.options.Schema.json_schema:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema + 12, // 20: grpc.gateway.protoc_gen_openapiv2.options.Schema.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 1, // 21: grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.JSONSchema.JSONSchemaSimpleTypes + 12, // 22: grpc.gateway.protoc_gen_openapiv2.options.Tag.external_docs:type_name -> grpc.gateway.protoc_gen_openapiv2.options.ExternalDocumentation + 28, // 23: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.security:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry + 2, // 24: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.type:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Type + 3, // 25: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.in:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.In + 4, // 26: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.flow:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.Flow + 19, // 27: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.scopes:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes + 29, // 28: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.extensions:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry + 31, // 29: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.security_requirement:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry + 32, // 30: grpc.gateway.protoc_gen_openapiv2.options.Scopes.scope:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Scopes.ScopeEntry + 8, // 31: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response + 33, // 32: grpc.gateway.protoc_gen_openapiv2.options.Swagger.ExtensionsEntry.value:type_name -> google.protobuf.Value + 8, // 33: grpc.gateway.protoc_gen_openapiv2.options.Operation.ResponsesEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Response + 33, // 34: grpc.gateway.protoc_gen_openapiv2.options.Operation.ExtensionsEntry.value:type_name -> google.protobuf.Value + 7, // 35: grpc.gateway.protoc_gen_openapiv2.options.Response.HeadersEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.Header + 33, // 36: grpc.gateway.protoc_gen_openapiv2.options.Response.ExtensionsEntry.value:type_name -> google.protobuf.Value + 33, // 37: grpc.gateway.protoc_gen_openapiv2.options.Info.ExtensionsEntry.value:type_name -> google.protobuf.Value + 17, // 38: grpc.gateway.protoc_gen_openapiv2.options.SecurityDefinitions.SecurityEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme + 33, // 39: grpc.gateway.protoc_gen_openapiv2.options.SecurityScheme.ExtensionsEntry.value:type_name -> google.protobuf.Value + 30, // 40: grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementEntry.value:type_name -> grpc.gateway.protoc_gen_openapiv2.options.SecurityRequirement.SecurityRequirementValue + 41, // [41:41] is the sub-list for method output_type + 41, // [41:41] is the sub-list for method input_type + 41, // [41:41] is the sub-list for extension type_name + 41, // [41:41] is the sub-list for extension extendee + 0, // [0:41] is the sub-list for field type_name } func init() { file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() } @@ -2437,7 +2221,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Response); i { + switch v := v.(*Header); i { case 0: return &v.state case 1: @@ -2449,7 +2233,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Info); i { + switch v := v.(*Response); i { case 0: return &v.state case 1: @@ -2461,7 +2245,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Contact); i { + switch v := v.(*Info); i { case 0: return &v.state case 1: @@ -2473,7 +2257,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*License); i { + switch v := v.(*Contact); i { case 0: return &v.state case 1: @@ -2485,7 +2269,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExternalDocumentation); i { + switch v := v.(*License); i { case 0: return &v.state case 1: @@ -2497,7 +2281,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Schema); i { + switch v := v.(*ExternalDocumentation); i { case 0: return &v.state case 1: @@ -2509,7 +2293,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONSchema); i { + switch v := v.(*Schema); i { case 0: return &v.state case 1: @@ -2521,7 +2305,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Tag); i { + switch v := v.(*JSONSchema); i { case 0: return &v.state case 1: @@ -2533,7 +2317,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SecurityDefinitions); i { + switch v := v.(*Tag); i { case 0: return &v.state case 1: @@ -2545,7 +2329,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SecurityScheme); i { + switch v := v.(*SecurityDefinitions); i { case 0: return &v.state case 1: @@ -2557,7 +2341,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SecurityRequirement); i { + switch v := v.(*SecurityScheme); i { case 0: return &v.state case 1: @@ -2569,6 +2353,18 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { } } file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SecurityRequirement); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Scopes); i { case 0: return &v.state @@ -2580,7 +2376,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { return nil } } - file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SecurityRequirement_SecurityRequirementValue); i { case 0: return &v.state @@ -2599,7 +2395,7 @@ func file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_gateway_protoc_gen_openapiv2_options_openapiv2_proto_rawDesc, NumEnums: 5, - NumMessages: 26, + NumMessages: 28, NumExtensions: 0, NumServices: 0, }, diff --git a/gateway/protoc-gen-openapiv2/options/openapiv2.proto b/gateway/protoc-gen-openapiv2/options/openapiv2.proto index 41add95..9d078a5 100644 --- a/gateway/protoc-gen-openapiv2/options/openapiv2.proto +++ b/gateway/protoc-gen-openapiv2/options/openapiv2.proto @@ -172,6 +172,51 @@ message Operation { map extensions = 13; } +// `Header` is a representation of OpenAPI v2 specification's Header object. +// +// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject +// +message Header { + // `Description` is a short description of the header. + string description = 1; + // The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported. + string type = 2; + // `Format` The extending format for the previously mentioned type. + string format = 3; + // field 4 is reserved for 'items', but in OpenAPI-specific way. + reserved 4; + // field 5 is reserved `Collection Format` Determines the format of the array if type array is used. + reserved 5; + // `Default` Declares the value of the header that the server will use if none is provided. + // See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2. + // Unlike JSON Schema this value MUST conform to the defined type for the header. + string default = 6; + // field 7 is reserved for 'maximum'. + reserved 7; + // field 8 is reserved for 'exclusiveMaximum'. + reserved 8; + // field 9 is reserved for 'minimum'. + reserved 9; + // field 10 is reserved for 'exclusiveMinimum'. + reserved 10; + // field 11 is reserved for 'maxLength'. + reserved 11; + // field 12 is reserved for 'minLength'. + reserved 12; + // 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3. + string pattern = 13; + // field 14 is reserved for 'maxItems'. + reserved 14; + // field 15 is reserved for 'minItems'. + reserved 15; + // field 16 is reserved for 'uniqueItems'. + reserved 16; + // field 17 is reserved for 'enum'. + reserved 17; + // field 18 is reserved for 'multipleOf'. + reserved 18; +} + // `Response` is a representation of OpenAPI v2 specification's Response object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject @@ -183,8 +228,10 @@ message Response { // `Schema` optionally defines the structure of the response. // If `Schema` is not provided, it means there is no content to the response. Schema schema = 2; - // field 3 is reserved for 'headers'. - reserved 3; + // `Headers` A list of headers that are sent with the response. + // `Header` name is expected to be a string in the canonical format of the MIME header key + // See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey + map headers = 3; // `Examples` gives per-mimetype response examples. // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object map examples = 4; @@ -364,7 +411,7 @@ message Schema { // // Id represents the message identifier. // string id = 1; [ // (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { -// {description: "The unique identifier of the simple message." +// description: "The unique identifier of the simple message." // }]; // } // @@ -388,9 +435,10 @@ message JSONSchema { string description = 6; string default = 7; bool read_only = 8; - // field 9 is reserved for 'examples', which is omitted from OpenAPI v2 in - // favor of 'example' field. - reserved 9; + // A free-form property to include a JSON example of this field. This is copied + // verbatim to the output swagger.json. Quotes must be escaped. + // This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject + string example = 9; double multiple_of = 10; // Maximum represents an inclusive upper limit for a numeric instance. The // value of MUST be a number, @@ -443,9 +491,11 @@ message JSONSchema { } repeated JSONSchemaSimpleTypes type = 35; + // `Format` + string format = 36; // following fields are reserved, as the properties have been omitted from - // OpenAPI v2: format, contentMediaType, contentEncoding, if, then, else - reserved 36 to 41; + // OpenAPI v2: contentMediaType, contentEncoding, if, then, else + reserved 37 to 41; // field 42 is reserved for 'allOf', but in OpenAPI-specific way. // TODO(ivucica): add 'allOf'? reserved 42; @@ -453,6 +503,8 @@ message JSONSchema { // OpenAPI v2: // anyOf, oneOf, not reserved 43 to 45; + // Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1 + repeated string enum = 46; } // `Tag` is a representation of OpenAPI v2 specification's Tag object. diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index e55634d..55a2770 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -3,45 +3,46 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "runtime", srcs = glob( ["*.go"], exclude = ["*_test.go"], ), importpath = "github.com/binchencoder/ease-gateway/gateway/runtime", deps = [ + "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", "//gateway/internal:go_default_library", - "//httpoptions:go_default_library", + "//httpoptions", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", "@com_github_binchencoder_letsgo//grpc:go_default_library", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", "@com_github_golang_protobuf//ptypes:go_default_library_gen", - "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//internal/httprule:go_default_library", "@com_github_pborman_uuid//:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", "@go_googleapis//google/api:httpbody_go_proto", - "@io_bazel_rules_go//proto/wkt:duration_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", - "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//grpclog:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", - "@org_golang_google_protobuf//encoding/protojson:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", - "@org_golang_google_protobuf//reflect/protoregistry:go_default_library", "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//codes", + "@org_golang_google_grpc//grpclog", + "@org_golang_google_grpc//health/grpc_health_v1", + "@org_golang_google_grpc//metadata", + "@org_golang_google_grpc//status", + "@org_golang_google_protobuf//encoding/protojson", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//reflect/protoreflect", + "@org_golang_google_protobuf//reflect/protoregistry", + "@org_golang_google_protobuf//types/known/durationpb", + "@org_golang_google_protobuf//types/known/timestamppb", + "@org_golang_google_protobuf//types/known/wrapperspb", "@org_golang_x_net//context:go_default_library", ], ) go_test( - name = "go_default_test", + name = "runtime_test", size = "small", srcs = [ "balancer_test.go", @@ -52,39 +53,40 @@ go_test( "marshal_httpbodyproto_test.go", "marshaler_registry_test.go", "mux_test.go", - "pattern_test.go", - "query_test.go", ], - embed = [":go_default_library"], + embed = [":runtime"], deps = [ "//examples/internal/proto/examplepb:go_default_library", "//gateway/internal:go_default_library", "//gateway/runtime/internal/examplepb:go_default_library", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", "//httpoptions:go_default_library", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//runtime/internal/examplepb:go_default_library", - "@com_github_golang_protobuf//ptypes:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_google_go_cmp//cmp:go_default_library", - "@com_github_google_go_cmp//cmp/cmpopts:go_default_library", + "@com_github_google_go_cmp//cmp", + "@com_github_google_go_cmp//cmp/cmpopts", "@go_googleapis//google/api:httpbody_go_proto", "@go_googleapis//google/rpc:errdetails_go_proto", "@go_googleapis//google/rpc:status_go_proto", - "@io_bazel_rules_go//proto/wkt:duration_go_proto", - "@io_bazel_rules_go//proto/wkt:empty_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@io_bazel_rules_go//proto/wkt:struct_go_proto", - "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", - "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", - "@org_golang_google_protobuf//encoding/protojson:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//testing/protocmp:go_default_library", "@org_golang_google_grpc//:go_default_library", - "@org_golang_x_net//context:go_default_library", + "@org_golang_google_grpc//codes", + "@org_golang_google_grpc//health/grpc_health_v1", + "@org_golang_google_grpc//metadata", + "@org_golang_google_grpc//status", + "@org_golang_google_protobuf//encoding/protojson", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//testing/protocmp", + "@org_golang_google_protobuf//types/known/durationpb", + "@org_golang_google_protobuf//types/known/emptypb", + "@org_golang_google_protobuf//types/known/structpb", + "@org_golang_google_protobuf//types/known/timestamppb", + "@org_golang_google_protobuf//types/known/wrapperspb", ], ) + +alias( + name = "go_default_library", + actual = ":runtime", + visibility = ["//visibility:public"], +) diff --git a/gateway/runtime/context.go b/gateway/runtime/context.go index 2c249eb..b5d1e6c 100644 --- a/gateway/runtime/context.go +++ b/gateway/runtime/context.go @@ -41,7 +41,24 @@ var ( DefaultContextTimeout = 0 * time.Second ) -type rpcMethodKey struct{} +// malformedHTTPHeaders lists the headers that the gRPC server may reject outright as malformed. +// See https://github.com/grpc/grpc-go/pull/4803#issuecomment-986093310 for more context. +var malformedHTTPHeaders = map[string]struct{}{ + "connection": {}, +} + +type ( + rpcMethodKey struct{} + httpPathPatternKey struct{} + + AnnotateContextOption func(ctx context.Context) context.Context +) + +func WithHTTPPathPattern(pattern string) AnnotateContextOption { + return func(ctx context.Context) context.Context { + return withHTTPPathPattern(ctx, pattern) + } +} func decodeBinHeader(v string) ([]byte, error) { if len(v)%4 == 0 { @@ -58,8 +75,8 @@ At a minimum, the RemoteAddr is included in the fashion of "X-Forwarded-For", except that the forwarded destination is not another HTTP service but rather a gRPC service. */ -func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, error) { - ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName) +func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string, options ...AnnotateContextOption) (context.Context, error) { + ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName, options...) if err != nil { return nil, err } @@ -72,8 +89,8 @@ func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM // AnnotateIncomingContext adds context information such as metadata from the request. // Attach metadata as incoming context. -func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, error) { - ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName) +func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string, options ...AnnotateContextOption) (context.Context, error) { + ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName, options...) if err != nil { return nil, err } @@ -84,8 +101,11 @@ func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Reque return metadata.NewIncomingContext(ctx, md), nil } -func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, metadata.MD, error) { +func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string, options ...AnnotateContextOption) (context.Context, metadata.MD, error) { ctx = withRPCMethod(ctx, rpcMethodName) + for _, o := range options { + ctx = o(ctx) + } var pairs []string timeout := DefaultContextTimeout if tm := req.Header.Get(metadataGrpcTimeout); tm != "" { @@ -135,6 +155,7 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM } if timeout != 0 { + //nolint:govet // The context outlives this function ctx, _ = context.WithTimeout(ctx, timeout) } if len(pairs) == 0 { @@ -293,6 +314,13 @@ func isPermanentHTTPHeader(hdr string) bool { return false } +// isMalformedHTTPHeader checks whether header belongs to the list of +// "malformed headers" and would be rejected by the gRPC server. +func isMalformedHTTPHeader(header string) bool { + _, isMalformed := malformedHTTPHeaders[strings.ToLower(header)] + return isMalformed +} + // RPCMethod returns the method string for the server context. The returned // string is in the format of "/package.service/method". func RPCMethod(ctx context.Context) (string, bool) { @@ -310,3 +338,21 @@ func RPCMethod(ctx context.Context) (string, bool) { func withRPCMethod(ctx context.Context, rpcMethodName string) context.Context { return context.WithValue(ctx, rpcMethodKey{}, rpcMethodName) } + +// HTTPPathPattern returns the HTTP path pattern string relating to the HTTP handler, if one exists. +// The format of the returned string is defined by the google.api.http path template type. +func HTTPPathPattern(ctx context.Context) (string, bool) { + m := ctx.Value(httpPathPatternKey{}) + if m == nil { + return "", false + } + ms, ok := m.(string) + if !ok { + return "", false + } + return ms, true +} + +func withHTTPPathPattern(ctx context.Context, httpPathPattern string) context.Context { + return context.WithValue(ctx, httpPathPatternKey{}, httpPathPattern) +} diff --git a/gateway/runtime/context_test.go b/gateway/runtime/context_test.go index b618f60..76f79d8 100644 --- a/gateway/runtime/context_test.go +++ b/gateway/runtime/context_test.go @@ -20,12 +20,13 @@ const ( func TestAnnotateContext_WorksWithEmpty(t *testing.T) { ctx := context.Background() expectedRPCName := "/example.Example/Example" - request, err := http.NewRequest("GET", "http://www.example.com", nil) + expectedHTTPPathPattern := "/v1" + request, err := http.NewRequest("GET", "http://www.example.com/v1", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) } request.Header.Add("Some-Irrelevant-Header", "some value") - annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) + annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -39,7 +40,8 @@ func TestAnnotateContext_WorksWithEmpty(t *testing.T) { func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) { ctx := context.Background() expectedRPCName := "/example.Example/Example" - request, err := http.NewRequest("GET", "http://www.example.com", nil) + expectedHTTPPathPattern := "/v1" + request, err := http.NewRequest("GET", "http://www.example.com/v1", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) } @@ -48,7 +50,7 @@ func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) { request.Header.Add("Grpc-Metadata-Foo-BAZ", "Value2") request.Header.Add("Grpc-Metadata-foo-bAz", "Value3") request.Header.Add("Authorization", "Token 1234567890") - annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) + annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) if err != nil { t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) return @@ -74,6 +76,12 @@ func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) { } else if m != expectedRPCName { t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) } + + if m, ok := runtime.HTTPPathPattern(annotated); !ok { + t.Errorf("runtime.HTTPPathPattern(annotated) failed with no value; want %s", expectedHTTPPathPattern) + } else if m != expectedHTTPPathPattern { + t.Errorf("runtime.HTTPPathPattern(annotated) failed with %s; want %s", m, expectedHTTPPathPattern) + } } func TestAnnotateContext_ForwardGrpcBinaryMetadata(t *testing.T) { @@ -250,12 +258,13 @@ func TestAnnotateContext_SupportsCustomAnnotators(t *testing.T) { func TestAnnotateIncomingContext_WorksWithEmpty(t *testing.T) { ctx := context.Background() expectedRPCName := "/example.Example/Example" - request, err := http.NewRequest("GET", "http://www.example.com", nil) + expectedHTTPPathPattern := "/v1" + request, err := http.NewRequest("GET", "http://www.example.com/v1", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) } request.Header.Add("Some-Irrelevant-Header", "some value") - annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) + annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -274,7 +283,8 @@ func TestAnnotateIncomingContext_WorksWithEmpty(t *testing.T) { func TestAnnotateIncomingContext_ForwardsGrpcMetadata(t *testing.T) { ctx := context.Background() expectedRPCName := "/example.Example/Example" - request, err := http.NewRequest("GET", "http://www.example.com", nil) + expectedHTTPPathPattern := "/v1" + request, err := http.NewRequest("GET", "http://www.example.com/v1", nil) if err != nil { t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) } @@ -283,7 +293,7 @@ func TestAnnotateIncomingContext_ForwardsGrpcMetadata(t *testing.T) { request.Header.Add("Grpc-Metadata-Foo-BAZ", "Value2") request.Header.Add("Grpc-Metadata-foo-bAz", "Value3") request.Header.Add("Authorization", "Token 1234567890") - annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) + annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) if err != nil { t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) return @@ -309,6 +319,11 @@ func TestAnnotateIncomingContext_ForwardsGrpcMetadata(t *testing.T) { } else if m != expectedRPCName { t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) } + if m, ok := runtime.HTTPPathPattern(annotated); !ok { + t.Errorf("runtime.HTTPPathPattern(annotated) failed with no value; want %s", expectedHTTPPathPattern) + } else if m != expectedHTTPPathPattern { + t.Errorf("runtime.HTTPPathPattern(annotated) failed with %s; want %s", m, expectedHTTPPathPattern) + } } func TestAnnotateIncomingContext_ForwardGrpcBinaryMetadata(t *testing.T) { diff --git a/gateway/runtime/convert.go b/gateway/runtime/convert.go index e122dd3..cfa5407 100644 --- a/gateway/runtime/convert.go +++ b/gateway/runtime/convert.go @@ -6,10 +6,10 @@ import ( "strconv" "strings" - durationpb "github.com/golang/protobuf/ptypes/duration" - timestamppb "github.com/golang/protobuf/ptypes/timestamp" - wrapperspb "github.com/golang/protobuf/ptypes/wrappers" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" ) // String just returns the given string. @@ -207,6 +207,7 @@ func BytesSlice(val, sep string) ([][]byte, error) { // Timestamp converts the given RFC3339 formatted string into a timestamp.Timestamp. func Timestamp(val string) (*timestamppb.Timestamp, error) { var r timestamppb.Timestamp + val = strconv.Quote(strings.Trim(val, `"`)) unmarshaler := &protojson.UnmarshalOptions{} err := unmarshaler.Unmarshal([]byte(val), &r) if err != nil { @@ -218,6 +219,7 @@ func Timestamp(val string) (*timestamppb.Timestamp, error) { // Duration converts the given string into a timestamp.Duration. func Duration(val string) (*durationpb.Duration, error) { var r durationpb.Duration + val = strconv.Quote(strings.Trim(val, `"`)) unmarshaler := &protojson.UnmarshalOptions{} err := unmarshaler.Unmarshal([]byte(val), &r) if err != nil { @@ -263,7 +265,7 @@ func EnumSlice(val, sep string, enumValMap map[string]int32) ([]int32, error) { } /* - Support fot google.protobuf.wrappers on top of primitive types + Support for google.protobuf.wrappers on top of primitive types */ // StringValue well-known type support as wrapper around string type diff --git a/gateway/runtime/convert_test.go b/gateway/runtime/convert_test.go index 2c95fa1..457c0f8 100644 --- a/gateway/runtime/convert_test.go +++ b/gateway/runtime/convert_test.go @@ -3,11 +3,11 @@ package runtime_test import ( "testing" - durationpb "github.com/golang/protobuf/ptypes/duration" - timestamppb "github.com/golang/protobuf/ptypes/timestamp" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" ) func TestConvertTimestamp(t *testing.T) { @@ -26,6 +26,15 @@ func TestConvertTimestamp(t *testing.T) { }, wanterr: false, }, + { + name: "a valid RFC3339 timestamp without double quotation", + input: "2016-05-10T10:19:13.123Z", + output: ×tamppb.Timestamp{ + Seconds: 1462875553, + Nanos: 123000000, + }, + wanterr: false, + }, { name: "invalid timestamp", input: `"05-10-2016T10:19:13.123Z"`, @@ -82,6 +91,15 @@ func TestConvertDuration(t *testing.T) { }, wanterr: false, }, + { + name: "a valid duration without double quotation", + input: "123.456s", + output: &durationpb.Duration{ + Seconds: 123, + Nanos: 456000000, + }, + wanterr: false, + }, { name: "invalid duration", input: `"123years"`, diff --git a/gateway/runtime/errors.go b/gateway/runtime/errors.go index 43fbb9c..0acfcda 100644 --- a/gateway/runtime/errors.go +++ b/gateway/runtime/errors.go @@ -2,9 +2,9 @@ package runtime import ( "context" + "errors" "io" "net/http" - "strings" "github.com/golang/protobuf/jsonpb" @@ -25,6 +25,17 @@ type StreamErrorHandlerFunc func(context.Context, error) *status.Status // RoutingErrorHandlerFunc is the signature used to configure error handling for routing errors. type RoutingErrorHandlerFunc func(context.Context, *ServeMux, Marshaler, http.ResponseWriter, *http.Request, int) +// HTTPStatusError is the error to use when needing to provide a different HTTP status code for an error +// passed to the DefaultRoutingErrorHandler. +type HTTPStatusError struct { + HTTPStatus int + Err error +} + +func (e *HTTPStatusError) Error() string { + return e.Err.Error() +} + // HTTPStatusFromCode converts a gRPC error code into the corresponding HTTP response status. // See: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto func HTTPStatusFromCode(code codes.Code) int { @@ -77,6 +88,10 @@ func HTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.R // DefaultHTTPErrorHandler is the default error handler. // If "err" is a gRPC Status, the function replies with the status code mapped by HTTPStatusFromCode. +// If "err" is a HTTPStatusError, the function replies with the status code provide by that struct. This is +// intended to allow passing through of specific statuses via the function set via WithRoutingErrorHandler +// for the ServeMux constructor to handle edge cases which the standard mappings in HTTPStatusFromCode +// are insufficient for. // If otherwise, it replies with http.StatusInternalServerError. // // The response body written by this function is a Status message marshaled by the Marshaler. @@ -84,6 +99,11 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh // return Internal when Marshal failed const fallback = `{"code": 13, "message": "failed to marshal error message"}` + var customStatus *HTTPStatusError + if errors.As(err, &customStatus) { + err = customStatus.Err + } + s := status.Convert(err) pb := s.Proto() @@ -93,6 +113,9 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh contentType := marshaler.ContentType(pb) w.Header().Set("Content-Type", contentType) + if s.Code() == codes.Unauthenticated { + w.Header().Set("WWW-Authenticate", s.Message()) + } e := fpb.Error{} desc := s.Message() if erru := jsonpb.UnmarshalString(desc, &e); erru != nil { @@ -103,7 +126,7 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh Error: &e, Message: s.Message(), Code: int32(s.Code()), - Details: s.Proto().GetDetails(), + Details: pb.GetDetails(), } buf, merr := marshaler.Marshal(body) @@ -128,21 +151,24 @@ func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marsh // is acceptable, as described in Section 4.3, a server SHOULD NOT // generate trailer fields that it believes are necessary for the user // agent to receive. - var wantsTrailers bool + doForwardTrailers := requestAcceptsTrailers(r) - if te := r.Header.Get("TE"); strings.Contains(strings.ToLower(te), "trailers") { - wantsTrailers = true + if doForwardTrailers { handleForwardResponseTrailerHeader(w, md) w.Header().Set("Transfer-Encoding", "chunked") } st := HTTPStatusFromCode(s.Code()) + if customStatus != nil { + st = customStatus.HTTPStatus + } + w.WriteHeader(st) if _, err := w.Write(buf); err != nil { grpclog.Infof("Failed to write response: %v", err) } - if wantsTrailers { + if doForwardTrailers { handleForwardResponseTrailer(w, md) } } diff --git a/gateway/runtime/errors_test.go b/gateway/runtime/errors_test.go index 7f91013..a761001 100644 --- a/gateway/runtime/errors_test.go +++ b/gateway/runtime/errors_test.go @@ -61,6 +61,16 @@ func TestDefaultHTTPError(t *testing.T) { contentType: "Custom-Content-Type", msg: "example error", }, + { + err: &runtime.HTTPStatusError{ + HTTPStatus: http.StatusMethodNotAllowed, + Err: status.Error(codes.Unimplemented, http.StatusText(http.StatusMethodNotAllowed)), + }, + status: http.StatusMethodNotAllowed, + marshaler: &runtime.JSONPb{}, + contentType: "application/json", + msg: "Method Not Allowed", + }, } { t.Run(strconv.Itoa(i), func(t *testing.T) { w := httptest.NewRecorder() diff --git a/gateway/runtime/fieldmask.go b/gateway/runtime/fieldmask.go index bdaa79d..0138ed2 100644 --- a/gateway/runtime/fieldmask.go +++ b/gateway/runtime/fieldmask.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io" + "sort" "google.golang.org/genproto/protobuf/field_mask" "google.golang.org/protobuf/proto" @@ -32,7 +33,6 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field } queue := []fieldMaskPathItem{{node: root, msg: msg.ProtoReflect()}} - var repeatedChild *fieldMaskPathItem for len(queue) > 0 { // dequeue an item item := queue[0] @@ -63,6 +63,17 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field continue } + if isProtobufAnyMessage(fd.Message()) { + _, hasTypeField := v.(map[string]interface{})["@type"] + if hasTypeField { + queue = append(queue, fieldMaskPathItem{path: k}) + continue + } else { + return nil, fmt.Errorf("could not find field @type in %q in message %q", k, item.msg.Descriptor().FullName()) + } + + } + child := fieldMaskPathItem{ node: v, } @@ -74,14 +85,9 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field switch { case fd.IsList(), fd.IsMap(): - if repeatedChild != nil { - // This is implied by the rule that any repeated fields must be - // last in the paths. - // Ref: https://github.com/protocolbuffers/protobuf/blob/6b0ff74ecf63e26c7315f6745de36aff66deb59d/src/google/protobuf/field_mask.proto#L85-L86 - return nil, fmt.Errorf("only one repeated value is allowed per field_mask") - } - repeatedChild = &child - // Don't add to paths until the end + // As per: https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/field_mask.proto#L85-L86 + // Do not recurse into repeated fields. The repeated field goes on the end of the path and we stop. + fm.Paths = append(fm.Paths, child.path) case fd.Message() != nil: child.msg = item.msg.Get(fd).Message() fallthrough @@ -95,15 +101,17 @@ func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.Field } } - // Add any repeated fields last, as per - // https://github.com/protocolbuffers/protobuf/blob/6b0ff74ecf63e26c7315f6745de36aff66deb59d/src/google/protobuf/field_mask.proto#L85-L86 - if repeatedChild != nil { - fm.Paths = append(fm.Paths, repeatedChild.path) - } + // Sort for deterministic output in the presence + // of repeated fields. + sort.Strings(fm.Paths) return fm, nil } +func isProtobufAnyMessage(md protoreflect.MessageDescriptor) bool { + return md != nil && (md.FullName() == "google.protobuf.Any") +} + func isDynamicProtoMessage(md protoreflect.MessageDescriptor) bool { return md != nil && (md.FullName() == "google.protobuf.Struct" || md.FullName() == "google.protobuf.Value") } diff --git a/gateway/runtime/handler.go b/gateway/runtime/handler.go index 2628c2b..d1e21df 100644 --- a/gateway/runtime/handler.go +++ b/gateway/runtime/handler.go @@ -6,6 +6,7 @@ import ( "io" "net/http" "net/textproto" + "strings" "google.golang.org/genproto/googleapis/api/httpbody" "google.golang.org/grpc/codes" @@ -137,6 +138,19 @@ func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marsha } handleForwardResponseServerMetadata(w, mux, md) + + // RFC 7230 https://tools.ietf.org/html/rfc7230#section-4.1.2 + // Unless the request includes a TE header field indicating "trailers" + // is acceptable, as described in Section 4.3, a server SHOULD NOT + // generate trailer fields that it believes are necessary for the user + // agent to receive. + doForwardTrailers := requestAcceptsTrailers(req) + + if doForwardTrailers { + handleForwardResponseTrailerHeader(w, md) + w.Header().Set("Transfer-Encoding", "chunked") + } + handleForwardResponseTrailerHeader(w, md) contentType := marshaler.ContentType(resp) @@ -163,7 +177,14 @@ func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marsha grpclog.Infof("Failed to write response: %v", err) } - handleForwardResponseTrailer(w, md) + if doForwardTrailers { + handleForwardResponseTrailer(w, md) + } +} + +func requestAcceptsTrailers(req *http.Request) bool { + te := req.Header.Get("TE") + return strings.Contains(strings.ToLower(te), "trailers") } func handleForwardResponseOptions(ctx context.Context, w http.ResponseWriter, resp proto.Message, opts []func(context.Context, http.ResponseWriter, proto.Message) error) error { @@ -181,10 +202,12 @@ func handleForwardResponseOptions(ctx context.Context, w http.ResponseWriter, re func handleForwardResponseStreamError(ctx context.Context, wroteHeader bool, marshaler Marshaler, w http.ResponseWriter, req *http.Request, mux *ServeMux, err error) { st := mux.streamErrorHandler(ctx, err) + msg := errorChunk(st) if !wroteHeader { + w.Header().Set("Content-Type", marshaler.ContentType(msg)) w.WriteHeader(HTTPStatusFromCode(st.Code())) } - buf, merr := marshaler.Marshal(errorChunk(st)) + buf, merr := marshaler.Marshal(msg) if merr != nil { grpclog.Infof("Failed to marshal an error: %v", merr) return diff --git a/gateway/runtime/handler_test.go b/gateway/runtime/handler_test.go index d0c171e..13de50d 100644 --- a/gateway/runtime/handler_test.go +++ b/gateway/runtime/handler_test.go @@ -111,6 +111,9 @@ func TestForwardResponseStream(t *testing.T) { t.Errorf("Failed to read response body with %v", err) } w.Body.Close() + if len(body) > 0 && w.Header.Get("Content-Type") != "application/json" { + t.Errorf("Content-Type %s want application/json", w.Header.Get("Content-Type")) + } var want []byte for i, msg := range tt.msgs { @@ -241,6 +244,9 @@ func TestForwardResponseStreamCustomMarshaler(t *testing.T) { t.Errorf("Failed to read response body with %v", err) } w.Body.Close() + if len(body) > 0 && w.Header.Get("Content-Type") != "Custom-Content-Type" { + t.Errorf("Content-Type %s want Custom-Content-Type", w.Header.Get("Content-Type")) + } var want []byte for _, msg := range tt.msgs { diff --git a/gateway/runtime/internal/examplepb/BUILD.bazel b/gateway/runtime/internal/examplepb/BUILD.bazel index c6f1a1d..2acced4 100644 --- a/gateway/runtime/internal/examplepb/BUILD.bazel +++ b/gateway/runtime/internal/examplepb/BUILD.bazel @@ -12,6 +12,7 @@ proto_library( "proto3.proto", ], deps = [ + "@com_google_protobuf//:any_proto", "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:empty_proto", "@com_google_protobuf//:field_mask_proto", @@ -34,7 +35,13 @@ go_proto_library( ) go_library( - name = "go_default_library", + name = "examplepb", embed = [":examplepb_go_proto"], importpath = "github.com/binchencoder/ease-gateway/gateway/runtime/internal/examplepb", ) + +alias( + name = "go_default_library", + actual = ":examplepb", + visibility = ["//runtime:__subpackages__"], +) diff --git a/gateway/runtime/internal/examplepb/proto3.pb.go b/gateway/runtime/internal/examplepb/proto3.pb.go old mode 100644 new mode 100755 index 023c967..faacca3 --- a/gateway/runtime/internal/examplepb/proto3.pb.go +++ b/gateway/runtime/internal/examplepb/proto3.pb.go @@ -1,19 +1,18 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: gateway/runtime/internal/examplepb/proto3.proto package examplepb import ( - proto "github.com/golang/protobuf/proto" - duration "github.com/golang/protobuf/ptypes/duration" - timestamp "github.com/golang/protobuf/ptypes/timestamp" - wrappers "github.com/golang/protobuf/ptypes/wrappers" - field_mask "google.golang.org/genproto/protobuf/field_mask" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" reflect "reflect" sync "sync" ) @@ -25,10 +24,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type EnumValue int32 const ( @@ -83,51 +78,53 @@ type Proto3Message struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Next number: 46 - Nested *Proto3Message `protobuf:"bytes,41,opt,name=nested,proto3" json:"nested,omitempty"` - FloatValue float32 `protobuf:"fixed32,42,opt,name=float_value,json=floatValue,proto3" json:"float_value,omitempty"` - DoubleValue float64 `protobuf:"fixed64,43,opt,name=double_value,json=doubleValue,proto3" json:"double_value,omitempty"` - Int64Value int64 `protobuf:"varint,3,opt,name=int64_value,json=int64Value,proto3" json:"int64_value,omitempty"` - Int32Value int32 `protobuf:"varint,4,opt,name=int32_value,json=int32Value,proto3" json:"int32_value,omitempty"` - Uint64Value uint64 `protobuf:"varint,5,opt,name=uint64_value,json=uint64Value,proto3" json:"uint64_value,omitempty"` - Uint32Value uint32 `protobuf:"varint,6,opt,name=uint32_value,json=uint32Value,proto3" json:"uint32_value,omitempty"` - BoolValue bool `protobuf:"varint,7,opt,name=bool_value,json=boolValue,proto3" json:"bool_value,omitempty"` - StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3" json:"string_value,omitempty"` - BytesValue []byte `protobuf:"bytes,9,opt,name=bytes_value,json=bytesValue,proto3" json:"bytes_value,omitempty"` - RepeatedValue []string `protobuf:"bytes,10,rep,name=repeated_value,json=repeatedValue,proto3" json:"repeated_value,omitempty"` - RepeatedMessage []*wrappers.UInt64Value `protobuf:"bytes,44,rep,name=repeated_message,json=repeatedMessage,proto3" json:"repeated_message,omitempty"` - EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"enum_value,omitempty"` - RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeatedEnum,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"repeated_enum,omitempty"` - TimestampValue *timestamp.Timestamp `protobuf:"bytes,13,opt,name=timestamp_value,json=timestampValue,proto3" json:"timestamp_value,omitempty"` - DurationValue *duration.Duration `protobuf:"bytes,14,opt,name=duration_value,json=durationValue,proto3" json:"duration_value,omitempty"` - FieldmaskValue *field_mask.FieldMask `protobuf:"bytes,15,opt,name=fieldmask_value,json=fieldmaskValue,proto3" json:"fieldmask_value,omitempty"` + Nested *Proto3Message `protobuf:"bytes,41,opt,name=nested,proto3" json:"nested,omitempty"` + FloatValue float32 `protobuf:"fixed32,42,opt,name=float_value,json=floatValue,proto3" json:"float_value,omitempty"` + DoubleValue float64 `protobuf:"fixed64,43,opt,name=double_value,json=doubleValue,proto3" json:"double_value,omitempty"` + Int64Value int64 `protobuf:"varint,3,opt,name=int64_value,json=int64Value,proto3" json:"int64_value,omitempty"` + Int32Value int32 `protobuf:"varint,4,opt,name=int32_value,json=int32Value,proto3" json:"int32_value,omitempty"` + Uint64Value uint64 `protobuf:"varint,5,opt,name=uint64_value,json=uint64Value,proto3" json:"uint64_value,omitempty"` + Uint32Value uint32 `protobuf:"varint,6,opt,name=uint32_value,json=uint32Value,proto3" json:"uint32_value,omitempty"` + BoolValue bool `protobuf:"varint,7,opt,name=bool_value,json=boolValue,proto3" json:"bool_value,omitempty"` + StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3" json:"string_value,omitempty"` + BytesValue []byte `protobuf:"bytes,9,opt,name=bytes_value,json=bytesValue,proto3" json:"bytes_value,omitempty"` + RepeatedValue []string `protobuf:"bytes,10,rep,name=repeated_value,json=repeatedValue,proto3" json:"repeated_value,omitempty"` + RepeatedMessage []*wrapperspb.UInt64Value `protobuf:"bytes,44,rep,name=repeated_message,json=repeatedMessage,proto3" json:"repeated_message,omitempty"` + EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"enum_value,omitempty"` + RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeatedEnum,proto3,enum=ease.gateway.runtime.internal.examplepb.EnumValue" json:"repeated_enum,omitempty"` + TimestampValue *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=timestamp_value,json=timestampValue,proto3" json:"timestamp_value,omitempty"` + DurationValue *durationpb.Duration `protobuf:"bytes,14,opt,name=duration_value,json=durationValue,proto3" json:"duration_value,omitempty"` + FieldmaskValue *fieldmaskpb.FieldMask `protobuf:"bytes,15,opt,name=fieldmask_value,json=fieldmaskValue,proto3" json:"fieldmask_value,omitempty"` // Types that are assignable to OneofValue: // *Proto3Message_OneofBoolValue // *Proto3Message_OneofStringValue - OneofValue isProto3Message_OneofValue `protobuf_oneof:"oneof_value"` - WrapperDoubleValue *wrappers.DoubleValue `protobuf:"bytes,17,opt,name=wrapper_double_value,json=wrapperDoubleValue,proto3" json:"wrapper_double_value,omitempty"` - WrapperFloatValue *wrappers.FloatValue `protobuf:"bytes,18,opt,name=wrapper_float_value,json=wrapperFloatValue,proto3" json:"wrapper_float_value,omitempty"` - WrapperInt64Value *wrappers.Int64Value `protobuf:"bytes,19,opt,name=wrapper_int64_value,json=wrapperInt64Value,proto3" json:"wrapper_int64_value,omitempty"` - WrapperInt32Value *wrappers.Int32Value `protobuf:"bytes,20,opt,name=wrapper_int32_value,json=wrapperInt32Value,proto3" json:"wrapper_int32_value,omitempty"` - WrapperUInt64Value *wrappers.UInt64Value `protobuf:"bytes,21,opt,name=wrapper_u_int64_value,json=wrapperUInt64Value,proto3" json:"wrapper_u_int64_value,omitempty"` - WrapperUInt32Value *wrappers.UInt32Value `protobuf:"bytes,22,opt,name=wrapper_u_int32_value,json=wrapperUInt32Value,proto3" json:"wrapper_u_int32_value,omitempty"` - WrapperBoolValue *wrappers.BoolValue `protobuf:"bytes,23,opt,name=wrapper_bool_value,json=wrapperBoolValue,proto3" json:"wrapper_bool_value,omitempty"` - WrapperStringValue *wrappers.StringValue `protobuf:"bytes,24,opt,name=wrapper_string_value,json=wrapperStringValue,proto3" json:"wrapper_string_value,omitempty"` - WrapperBytesValue *wrappers.BytesValue `protobuf:"bytes,25,opt,name=wrapper_bytes_value,json=wrapperBytesValue,proto3" json:"wrapper_bytes_value,omitempty"` - MapValue map[string]string `protobuf:"bytes,26,rep,name=map_value,json=mapValue,proto3" json:"map_value,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue2 map[string]int32 `protobuf:"bytes,27,rep,name=map_value2,json=mapValue2,proto3" json:"map_value2,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - MapValue3 map[int32]string `protobuf:"bytes,28,rep,name=map_value3,json=mapValue3,proto3" json:"map_value3,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue4 map[string]int64 `protobuf:"bytes,29,rep,name=map_value4,json=mapValue4,proto3" json:"map_value4,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - MapValue5 map[int64]string `protobuf:"bytes,30,rep,name=map_value5,json=mapValue5,proto3" json:"map_value5,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue6 map[string]uint32 `protobuf:"bytes,31,rep,name=map_value6,json=mapValue6,proto3" json:"map_value6,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - MapValue7 map[uint32]string `protobuf:"bytes,32,rep,name=map_value7,json=mapValue7,proto3" json:"map_value7,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue8 map[string]uint64 `protobuf:"bytes,33,rep,name=map_value8,json=mapValue8,proto3" json:"map_value8,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - MapValue9 map[uint64]string `protobuf:"bytes,34,rep,name=map_value9,json=mapValue9,proto3" json:"map_value9,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue10 map[string]float32 `protobuf:"bytes,35,rep,name=map_value10,json=mapValue10,proto3" json:"map_value10,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed32,2,opt,name=value,proto3"` - MapValue12 map[string]float64 `protobuf:"bytes,37,rep,name=map_value12,json=mapValue12,proto3" json:"map_value12,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"` - MapValue14 map[string]bool `protobuf:"bytes,39,rep,name=map_value14,json=mapValue14,proto3" json:"map_value14,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - MapValue15 map[bool]string `protobuf:"bytes,40,rep,name=map_value15,json=mapValue15,proto3" json:"map_value15,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapValue16 map[string]*wrappers.UInt64Value `protobuf:"bytes,45,rep,name=map_value16,json=mapValue16,proto3" json:"map_value16,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + OneofValue isProto3Message_OneofValue `protobuf_oneof:"oneof_value"` + // Types that are assignable to NestedOneofValue: + // *Proto3Message_NestedOneofValueOne + NestedOneofValue isProto3Message_NestedOneofValue `protobuf_oneof:"nested_oneof_value"` + WrapperDoubleValue *wrapperspb.DoubleValue `protobuf:"bytes,17,opt,name=wrapper_double_value,json=wrapperDoubleValue,proto3" json:"wrapper_double_value,omitempty"` + WrapperFloatValue *wrapperspb.FloatValue `protobuf:"bytes,18,opt,name=wrapper_float_value,json=wrapperFloatValue,proto3" json:"wrapper_float_value,omitempty"` + WrapperInt64Value *wrapperspb.Int64Value `protobuf:"bytes,19,opt,name=wrapper_int64_value,json=wrapperInt64Value,proto3" json:"wrapper_int64_value,omitempty"` + WrapperInt32Value *wrapperspb.Int32Value `protobuf:"bytes,20,opt,name=wrapper_int32_value,json=wrapperInt32Value,proto3" json:"wrapper_int32_value,omitempty"` + WrapperUInt64Value *wrapperspb.UInt64Value `protobuf:"bytes,21,opt,name=wrapper_u_int64_value,json=wrapperUInt64Value,proto3" json:"wrapper_u_int64_value,omitempty"` + WrapperUInt32Value *wrapperspb.UInt32Value `protobuf:"bytes,22,opt,name=wrapper_u_int32_value,json=wrapperUInt32Value,proto3" json:"wrapper_u_int32_value,omitempty"` + WrapperBoolValue *wrapperspb.BoolValue `protobuf:"bytes,23,opt,name=wrapper_bool_value,json=wrapperBoolValue,proto3" json:"wrapper_bool_value,omitempty"` + WrapperStringValue *wrapperspb.StringValue `protobuf:"bytes,24,opt,name=wrapper_string_value,json=wrapperStringValue,proto3" json:"wrapper_string_value,omitempty"` + WrapperBytesValue *wrapperspb.BytesValue `protobuf:"bytes,25,opt,name=wrapper_bytes_value,json=wrapperBytesValue,proto3" json:"wrapper_bytes_value,omitempty"` + MapValue map[string]string `protobuf:"bytes,26,rep,name=map_value,json=mapValue,proto3" json:"map_value,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue2 map[string]int32 `protobuf:"bytes,27,rep,name=map_value2,json=mapValue2,proto3" json:"map_value2,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue3 map[int32]string `protobuf:"bytes,28,rep,name=map_value3,json=mapValue3,proto3" json:"map_value3,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue4 map[string]int64 `protobuf:"bytes,29,rep,name=map_value4,json=mapValue4,proto3" json:"map_value4,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue5 map[int64]string `protobuf:"bytes,30,rep,name=map_value5,json=mapValue5,proto3" json:"map_value5,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue6 map[string]uint32 `protobuf:"bytes,31,rep,name=map_value6,json=mapValue6,proto3" json:"map_value6,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue7 map[uint32]string `protobuf:"bytes,32,rep,name=map_value7,json=mapValue7,proto3" json:"map_value7,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue8 map[string]uint64 `protobuf:"bytes,33,rep,name=map_value8,json=mapValue8,proto3" json:"map_value8,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue9 map[uint64]string `protobuf:"bytes,34,rep,name=map_value9,json=mapValue9,proto3" json:"map_value9,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue10 map[string]float32 `protobuf:"bytes,35,rep,name=map_value10,json=mapValue10,proto3" json:"map_value10,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed32,2,opt,name=value,proto3"` + MapValue12 map[string]float64 `protobuf:"bytes,37,rep,name=map_value12,json=mapValue12,proto3" json:"map_value12,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"` + MapValue14 map[string]bool `protobuf:"bytes,39,rep,name=map_value14,json=mapValue14,proto3" json:"map_value14,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + MapValue15 map[bool]string `protobuf:"bytes,40,rep,name=map_value15,json=mapValue15,proto3" json:"map_value15,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapValue16 map[string]*wrapperspb.UInt64Value `protobuf:"bytes,45,rep,name=map_value16,json=mapValue16,proto3" json:"map_value16,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Proto3Message) Reset() { @@ -239,7 +236,7 @@ func (x *Proto3Message) GetRepeatedValue() []string { return nil } -func (x *Proto3Message) GetRepeatedMessage() []*wrappers.UInt64Value { +func (x *Proto3Message) GetRepeatedMessage() []*wrapperspb.UInt64Value { if x != nil { return x.RepeatedMessage } @@ -260,21 +257,21 @@ func (x *Proto3Message) GetRepeatedEnum() []EnumValue { return nil } -func (x *Proto3Message) GetTimestampValue() *timestamp.Timestamp { +func (x *Proto3Message) GetTimestampValue() *timestamppb.Timestamp { if x != nil { return x.TimestampValue } return nil } -func (x *Proto3Message) GetDurationValue() *duration.Duration { +func (x *Proto3Message) GetDurationValue() *durationpb.Duration { if x != nil { return x.DurationValue } return nil } -func (x *Proto3Message) GetFieldmaskValue() *field_mask.FieldMask { +func (x *Proto3Message) GetFieldmaskValue() *fieldmaskpb.FieldMask { if x != nil { return x.FieldmaskValue } @@ -302,63 +299,77 @@ func (x *Proto3Message) GetOneofStringValue() string { return "" } -func (x *Proto3Message) GetWrapperDoubleValue() *wrappers.DoubleValue { +func (m *Proto3Message) GetNestedOneofValue() isProto3Message_NestedOneofValue { + if m != nil { + return m.NestedOneofValue + } + return nil +} + +func (x *Proto3Message) GetNestedOneofValueOne() *Proto3Message { + if x, ok := x.GetNestedOneofValue().(*Proto3Message_NestedOneofValueOne); ok { + return x.NestedOneofValueOne + } + return nil +} + +func (x *Proto3Message) GetWrapperDoubleValue() *wrapperspb.DoubleValue { if x != nil { return x.WrapperDoubleValue } return nil } -func (x *Proto3Message) GetWrapperFloatValue() *wrappers.FloatValue { +func (x *Proto3Message) GetWrapperFloatValue() *wrapperspb.FloatValue { if x != nil { return x.WrapperFloatValue } return nil } -func (x *Proto3Message) GetWrapperInt64Value() *wrappers.Int64Value { +func (x *Proto3Message) GetWrapperInt64Value() *wrapperspb.Int64Value { if x != nil { return x.WrapperInt64Value } return nil } -func (x *Proto3Message) GetWrapperInt32Value() *wrappers.Int32Value { +func (x *Proto3Message) GetWrapperInt32Value() *wrapperspb.Int32Value { if x != nil { return x.WrapperInt32Value } return nil } -func (x *Proto3Message) GetWrapperUInt64Value() *wrappers.UInt64Value { +func (x *Proto3Message) GetWrapperUInt64Value() *wrapperspb.UInt64Value { if x != nil { return x.WrapperUInt64Value } return nil } -func (x *Proto3Message) GetWrapperUInt32Value() *wrappers.UInt32Value { +func (x *Proto3Message) GetWrapperUInt32Value() *wrapperspb.UInt32Value { if x != nil { return x.WrapperUInt32Value } return nil } -func (x *Proto3Message) GetWrapperBoolValue() *wrappers.BoolValue { +func (x *Proto3Message) GetWrapperBoolValue() *wrapperspb.BoolValue { if x != nil { return x.WrapperBoolValue } return nil } -func (x *Proto3Message) GetWrapperStringValue() *wrappers.StringValue { +func (x *Proto3Message) GetWrapperStringValue() *wrapperspb.StringValue { if x != nil { return x.WrapperStringValue } return nil } -func (x *Proto3Message) GetWrapperBytesValue() *wrappers.BytesValue { +func (x *Proto3Message) GetWrapperBytesValue() *wrapperspb.BytesValue { if x != nil { return x.WrapperBytesValue } @@ -456,7 +467,7 @@ func (x *Proto3Message) GetMapValue15() map[bool]string { return nil } -func (x *Proto3Message) GetMapValue16() map[string]*wrappers.UInt64Value { +func (x *Proto3Message) GetMapValue16() map[string]*wrapperspb.UInt64Value { if x != nil { return x.MapValue16 } @@ -479,6 +490,16 @@ func (*Proto3Message_OneofBoolValue) isProto3Message_OneofValue() {} func (*Proto3Message_OneofStringValue) isProto3Message_OneofValue() {} +type isProto3Message_NestedOneofValue interface { + isProto3Message_NestedOneofValue() +} + +type Proto3Message_NestedOneofValueOne struct { + NestedOneofValueOne *Proto3Message `protobuf:"bytes,46,opt,name=nested_oneof_value_one,json=nestedOneofValueOne,proto3,oneof"` +} + +func (*Proto3Message_NestedOneofValueOne) isProto3Message_NestedOneofValue() {} + var File_gateway_runtime_internal_examplepb_proto3_proto protoreflect.FileDescriptor var file_gateway_runtime_internal_examplepb_proto3_proto_rawDesc = []byte{ @@ -495,7 +516,7 @@ var file_gateway_runtime_internal_examplepb_proto3_proto_rawDesc = []byte{ 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, - 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc7, 0x1f, + 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcc, 0x20, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4e, 0x0a, 0x06, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, @@ -557,205 +578,214 @@ var file_gateway_runtime_internal_examplepb_proto3_proto_rawDesc = []byte{ 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x14, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x64, 0x6f, - 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, - 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x66, 0x6c, - 0x6f, 0x61, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, - 0x61, 0x70, 0x70, 0x65, 0x72, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, - 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, - 0x65, 0x72, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, - 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, - 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x49, - 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4f, 0x0a, 0x15, 0x77, 0x72, 0x61, - 0x70, 0x70, 0x65, 0x72, 0x5f, 0x75, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, - 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x55, - 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4f, 0x0a, 0x15, 0x77, 0x72, - 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x75, 0x5f, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, - 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, - 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x77, - 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x10, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6c, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x14, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, - 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x18, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, - 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x19, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, - 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x61, 0x0a, 0x09, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x1a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, - 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x61, 0x70, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x32, 0x18, 0x1b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, + 0x75, 0x65, 0x12, 0x6d, 0x0a, 0x16, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x65, + 0x6f, 0x66, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x6f, 0x6e, 0x65, 0x18, 0x2e, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x01, 0x52, 0x13, 0x6e, 0x65, + 0x73, 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x65, 0x6f, 0x66, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x6e, + 0x65, 0x12, 0x4e, 0x0a, 0x14, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x75, + 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, + 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x66, 0x6c, 0x6f, + 0x61, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, + 0x70, 0x70, 0x65, 0x72, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, + 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, + 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, + 0x72, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, + 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x49, 0x6e, + 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4f, 0x0a, 0x15, 0x77, 0x72, 0x61, 0x70, + 0x70, 0x65, 0x72, 0x5f, 0x75, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x55, 0x49, + 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4f, 0x0a, 0x15, 0x77, 0x72, 0x61, + 0x70, 0x70, 0x65, 0x72, 0x5f, 0x75, 0x5f, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, + 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x55, + 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x77, 0x72, + 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x10, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6c, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x14, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x18, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x12, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x13, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, + 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x61, 0x0a, 0x09, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x1a, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x61, 0x70, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x32, 0x18, 0x1b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, + 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x33, 0x18, 0x1c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, + 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x33, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x33, + 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x18, 0x1d, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x35, 0x18, 0x1e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, + 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x12, 0x64, 0x0a, 0x0a, + 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x36, 0x18, 0x1f, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x36, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x37, + 0x18, 0x20, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, + 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, + 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x37, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, + 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x37, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x18, 0x21, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, + 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x12, 0x64, + 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x39, 0x18, 0x22, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x39, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x39, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x31, 0x30, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x12, 0x64, 0x0a, 0x0a, 0x6d, - 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x33, 0x18, 0x1c, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x33, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x33, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x18, - 0x1d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, - 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, - 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x35, 0x18, 0x1e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, + 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x12, 0x67, 0x0a, + 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x18, 0x25, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x31, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x31, 0x34, 0x18, 0x27, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x12, 0x64, 0x0a, - 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x36, 0x18, 0x1f, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x36, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x37, 0x18, 0x20, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, - 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, - 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x37, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, - 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x37, 0x12, 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x18, 0x21, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, + 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x12, + 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x18, 0x28, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, + 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, 0x18, 0x2d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 0x12, - 0x64, 0x0a, 0x0a, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x39, 0x18, 0x22, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x39, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6d, 0x61, 0x70, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x39, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x31, 0x30, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, - 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x12, 0x67, - 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x18, 0x25, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, - 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x18, 0x27, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, - 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, - 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x18, - 0x28, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, - 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, - 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x12, 0x67, 0x0a, 0x0b, 0x6d, 0x61, 0x70, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, 0x18, 0x2d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, - 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x72, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, - 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x31, 0x36, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 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, - 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 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, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, - 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x33, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 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, 0x3c, 0x0a, 0x0e, 0x4d, - 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 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, 0x03, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 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, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x36, 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, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x37, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 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, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, - 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, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x39, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 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, - 0x3d, 0x0a, 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 0x45, 0x6e, 0x74, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, + 0x36, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 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, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, - 0x0a, 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 0x45, 0x6e, 0x74, 0x72, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, + 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x32, 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, + 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, + 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x33, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 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, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, + 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x34, 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, 0x03, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 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, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x36, 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, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x37, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 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, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x38, 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, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x3c, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x39, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 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, 0x3d, + 0x0a, 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x30, 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, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, - 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, + 0x0f, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x32, 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, - 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, - 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 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, 0x5b, 0x0a, 0x0f, 0x4d, - 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x6f, 0x6e, 0x65, 0x6f, - 0x66, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x20, 0x0a, 0x09, 0x45, 0x6e, 0x75, 0x6d, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x12, 0x05, 0x0a, 0x01, 0x58, 0x10, 0x00, 0x12, 0x05, 0x0a, 0x01, 0x59, - 0x10, 0x01, 0x12, 0x05, 0x0a, 0x01, 0x5a, 0x10, 0x02, 0x42, 0x49, 0x5a, 0x47, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, - 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, + 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x34, 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, 0x08, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x4d, + 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x35, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 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, 0x5b, 0x0a, 0x0f, 0x4d, 0x61, + 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x36, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x6f, 0x6e, 0x65, 0x6f, 0x66, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x14, 0x0a, 0x12, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, + 0x5f, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x20, 0x0a, 0x09, + 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x05, 0x0a, 0x01, 0x58, 0x10, 0x00, + 0x12, 0x05, 0x0a, 0x01, 0x59, 0x10, 0x01, 0x12, 0x05, 0x0a, 0x01, 0x5a, 0x10, 0x02, 0x42, 0x49, + 0x5a, 0x47, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, + 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -773,34 +803,34 @@ func file_gateway_runtime_internal_examplepb_proto3_proto_rawDescGZIP() []byte { var file_gateway_runtime_internal_examplepb_proto3_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_gateway_runtime_internal_examplepb_proto3_proto_msgTypes = make([]protoimpl.MessageInfo, 15) var file_gateway_runtime_internal_examplepb_proto3_proto_goTypes = []interface{}{ - (EnumValue)(0), // 0: ease.gateway.runtime.internal.examplepb.EnumValue - (*Proto3Message)(nil), // 1: ease.gateway.runtime.internal.examplepb.Proto3Message - nil, // 2: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry - nil, // 3: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry - nil, // 4: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry - nil, // 5: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry - nil, // 6: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry - nil, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry - nil, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry - nil, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry - nil, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry - nil, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry - nil, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry - nil, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry - nil, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry - nil, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry - (*wrappers.UInt64Value)(nil), // 16: google.protobuf.UInt64Value - (*timestamp.Timestamp)(nil), // 17: google.protobuf.Timestamp - (*duration.Duration)(nil), // 18: google.protobuf.Duration - (*field_mask.FieldMask)(nil), // 19: google.protobuf.FieldMask - (*wrappers.DoubleValue)(nil), // 20: google.protobuf.DoubleValue - (*wrappers.FloatValue)(nil), // 21: google.protobuf.FloatValue - (*wrappers.Int64Value)(nil), // 22: google.protobuf.Int64Value - (*wrappers.Int32Value)(nil), // 23: google.protobuf.Int32Value - (*wrappers.UInt32Value)(nil), // 24: google.protobuf.UInt32Value - (*wrappers.BoolValue)(nil), // 25: google.protobuf.BoolValue - (*wrappers.StringValue)(nil), // 26: google.protobuf.StringValue - (*wrappers.BytesValue)(nil), // 27: google.protobuf.BytesValue + (EnumValue)(0), // 0: ease.gateway.runtime.internal.examplepb.EnumValue + (*Proto3Message)(nil), // 1: ease.gateway.runtime.internal.examplepb.Proto3Message + nil, // 2: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry + nil, // 3: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry + nil, // 4: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry + nil, // 5: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry + nil, // 6: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry + nil, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry + nil, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry + nil, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry + nil, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry + nil, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry + nil, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry + nil, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry + nil, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry + nil, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry + (*wrapperspb.UInt64Value)(nil), // 16: google.protobuf.UInt64Value + (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 18: google.protobuf.Duration + (*fieldmaskpb.FieldMask)(nil), // 19: google.protobuf.FieldMask + (*wrapperspb.DoubleValue)(nil), // 20: google.protobuf.DoubleValue + (*wrapperspb.FloatValue)(nil), // 21: google.protobuf.FloatValue + (*wrapperspb.Int64Value)(nil), // 22: google.protobuf.Int64Value + (*wrapperspb.Int32Value)(nil), // 23: google.protobuf.Int32Value + (*wrapperspb.UInt32Value)(nil), // 24: google.protobuf.UInt32Value + (*wrapperspb.BoolValue)(nil), // 25: google.protobuf.BoolValue + (*wrapperspb.StringValue)(nil), // 26: google.protobuf.StringValue + (*wrapperspb.BytesValue)(nil), // 27: google.protobuf.BytesValue } var file_gateway_runtime_internal_examplepb_proto3_proto_depIdxs = []int32{ 1, // 0: ease.gateway.runtime.internal.examplepb.Proto3Message.nested:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message @@ -810,35 +840,36 @@ var file_gateway_runtime_internal_examplepb_proto3_proto_depIdxs = []int32{ 17, // 4: ease.gateway.runtime.internal.examplepb.Proto3Message.timestamp_value:type_name -> google.protobuf.Timestamp 18, // 5: ease.gateway.runtime.internal.examplepb.Proto3Message.duration_value:type_name -> google.protobuf.Duration 19, // 6: ease.gateway.runtime.internal.examplepb.Proto3Message.fieldmask_value:type_name -> google.protobuf.FieldMask - 20, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_double_value:type_name -> google.protobuf.DoubleValue - 21, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_float_value:type_name -> google.protobuf.FloatValue - 22, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int64_value:type_name -> google.protobuf.Int64Value - 23, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int32_value:type_name -> google.protobuf.Int32Value - 16, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int64_value:type_name -> google.protobuf.UInt64Value - 24, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int32_value:type_name -> google.protobuf.UInt32Value - 25, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bool_value:type_name -> google.protobuf.BoolValue - 26, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_string_value:type_name -> google.protobuf.StringValue - 27, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bytes_value:type_name -> google.protobuf.BytesValue - 2, // 16: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry - 3, // 17: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value2:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry - 4, // 18: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value3:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry - 5, // 19: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value4:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry - 6, // 20: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value5:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry - 7, // 21: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value6:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry - 8, // 22: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value7:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry - 9, // 23: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value8:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry - 10, // 24: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value9:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry - 11, // 25: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value10:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry - 12, // 26: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value12:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry - 13, // 27: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value14:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry - 14, // 28: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value15:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry - 15, // 29: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value16:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry - 16, // 30: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry.value:type_name -> google.protobuf.UInt64Value - 31, // [31:31] is the sub-list for method output_type - 31, // [31:31] is the sub-list for method input_type - 31, // [31:31] is the sub-list for extension type_name - 31, // [31:31] is the sub-list for extension extendee - 0, // [0:31] is the sub-list for field type_name + 1, // 7: ease.gateway.runtime.internal.examplepb.Proto3Message.nested_oneof_value_one:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message + 20, // 8: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_double_value:type_name -> google.protobuf.DoubleValue + 21, // 9: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_float_value:type_name -> google.protobuf.FloatValue + 22, // 10: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int64_value:type_name -> google.protobuf.Int64Value + 23, // 11: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_int32_value:type_name -> google.protobuf.Int32Value + 16, // 12: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int64_value:type_name -> google.protobuf.UInt64Value + 24, // 13: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_u_int32_value:type_name -> google.protobuf.UInt32Value + 25, // 14: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bool_value:type_name -> google.protobuf.BoolValue + 26, // 15: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_string_value:type_name -> google.protobuf.StringValue + 27, // 16: ease.gateway.runtime.internal.examplepb.Proto3Message.wrapper_bytes_value:type_name -> google.protobuf.BytesValue + 2, // 17: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValueEntry + 3, // 18: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value2:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue2Entry + 4, // 19: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value3:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue3Entry + 5, // 20: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value4:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue4Entry + 6, // 21: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value5:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue5Entry + 7, // 22: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value6:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue6Entry + 8, // 23: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value7:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue7Entry + 9, // 24: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value8:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue8Entry + 10, // 25: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value9:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue9Entry + 11, // 26: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value10:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue10Entry + 12, // 27: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value12:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue12Entry + 13, // 28: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value14:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue14Entry + 14, // 29: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value15:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue15Entry + 15, // 30: ease.gateway.runtime.internal.examplepb.Proto3Message.map_value16:type_name -> ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry + 16, // 31: ease.gateway.runtime.internal.examplepb.Proto3Message.MapValue16Entry.value:type_name -> google.protobuf.UInt64Value + 32, // [32:32] is the sub-list for method output_type + 32, // [32:32] is the sub-list for method input_type + 32, // [32:32] is the sub-list for extension type_name + 32, // [32:32] is the sub-list for extension extendee + 0, // [0:32] is the sub-list for field type_name } func init() { file_gateway_runtime_internal_examplepb_proto3_proto_init() } @@ -863,6 +894,7 @@ func file_gateway_runtime_internal_examplepb_proto3_proto_init() { file_gateway_runtime_internal_examplepb_proto3_proto_msgTypes[0].OneofWrappers = []interface{}{ (*Proto3Message_OneofBoolValue)(nil), (*Proto3Message_OneofStringValue)(nil), + (*Proto3Message_NestedOneofValueOne)(nil), } type x struct{} out := protoimpl.TypeBuilder{ diff --git a/gateway/runtime/internal/examplepb/proto3.proto b/gateway/runtime/internal/examplepb/proto3.proto index a81fc4d..c5b0f10 100644 --- a/gateway/runtime/internal/examplepb/proto3.proto +++ b/gateway/runtime/internal/examplepb/proto3.proto @@ -10,7 +10,7 @@ import "google/protobuf/timestamp.proto"; import "google/protobuf/wrappers.proto"; message Proto3Message { - // Next number: 46 + // Next number: 47 Proto3Message nested = 41; float float_value = 42; double double_value = 43; @@ -32,6 +32,9 @@ message Proto3Message { bool oneof_bool_value = 1; string oneof_string_value = 2; } + oneof nested_oneof_value { + Proto3Message nested_oneof_value_one = 46; + } google.protobuf.DoubleValue wrapper_double_value = 17; google.protobuf.FloatValue wrapper_float_value = 18; google.protobuf.Int64Value wrapper_int64_value = 19; diff --git a/gateway/runtime/marshal_json_test.go b/gateway/runtime/marshal_json_test.go deleted file mode 100644 index f13c0b1..0000000 --- a/gateway/runtime/marshal_json_test.go +++ /dev/null @@ -1,255 +0,0 @@ -package runtime_test - -import ( - "bytes" - "encoding/json" - "reflect" - "strings" - "testing" - - emptypb "github.com/golang/protobuf/ptypes/empty" - timestamppb "github.com/golang/protobuf/ptypes/timestamp" - wrapperspb "github.com/golang/protobuf/ptypes/wrappers" - "github.com/google/go-cmp/cmp" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/testing/protocmp" -) - -func TestJSONBuiltinMarshal(t *testing.T) { - var m runtime.JSONBuiltin - msg := &examplepb.SimpleMessage{ - Id: "foo", - } - - buf, err := m.Marshal(msg) - if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success", msg, err) - } - - got := new(examplepb.SimpleMessage) - if err := json.Unmarshal(buf, got); err != nil { - t.Errorf("json.Unmarshal(%q, got) failed with %v; want success", buf, err) - } - if diff := cmp.Diff(got, msg, protocmp.Transform()); diff != "" { - t.Error(diff) - } -} - -func TestJSONBuiltinMarshalField(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinFieldFixtures { - buf, err := m.Marshal(fixt.data) - if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success", fixt.data, err) - } - if got, want := string(buf), fixt.json; got != want { - t.Errorf("got = %q; want %q; data = %#v", got, want, fixt.data) - } - } -} - -func TestJSONBuiltinMarshalFieldKnownErrors(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinKnownErrors { - buf, err := m.Marshal(fixt.data) - if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success", fixt.data, err) - } - if got, want := string(buf), fixt.json; got == want { - t.Errorf("surprisingly got = %q; as want %q; data = %#v", got, want, fixt.data) - } - } -} - -func TestJSONBuiltinsnmarshal(t *testing.T) { - var ( - m runtime.JSONBuiltin - got = new(examplepb.SimpleMessage) - - data = []byte(`{"id": "foo"}`) - ) - if err := m.Unmarshal(data, got); err != nil { - t.Errorf("m.Unmarshal(%q, got) failed with %v; want success", data, err) - } - - want := &examplepb.SimpleMessage{ - Id: "foo", - } - if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { - t.Errorf(diff) - } -} - -func TestJSONBuiltinUnmarshalField(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinFieldFixtures { - dest := alloc(reflect.TypeOf(fixt.data)) - if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err != nil { - t.Errorf("m.Unmarshal(%q, dest) failed with %v; want success", fixt.json, err) - } - - got, want := dest.Elem().Interface(), fixt.data - if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { - t.Error(diff) - } - } -} - -func alloc(t reflect.Type) reflect.Value { - if t == nil { - return reflect.ValueOf(new(interface{})) - } else { - return reflect.New(t) - } -} - -func TestJSONBuiltinUnmarshalFieldKnownErrors(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinKnownErrors { - dest := reflect.New(reflect.TypeOf(fixt.data)) - if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err == nil { - t.Errorf("m.Unmarshal(%q, dest) succeeded; want ane error", fixt.json) - } - } -} - -func TestJSONBuiltinEncoder(t *testing.T) { - var m runtime.JSONBuiltin - msg := &examplepb.SimpleMessage{ - Id: "foo", - } - - var buf bytes.Buffer - enc := m.NewEncoder(&buf) - if err := enc.Encode(msg); err != nil { - t.Errorf("enc.Encode(%v) failed with %v; want success", msg, err) - } - - got := new(examplepb.SimpleMessage) - if err := json.Unmarshal(buf.Bytes(), got); err != nil { - t.Errorf("json.Unmarshal(%q, got) failed with %v; want success", buf.String(), err) - } - if diff := cmp.Diff(got, msg, protocmp.Transform()); diff != "" { - t.Error(diff) - } -} - -func TestJSONBuiltinEncoderFields(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinFieldFixtures { - var buf bytes.Buffer - enc := m.NewEncoder(&buf) - if err := enc.Encode(fixt.data); err != nil { - t.Errorf("enc.Encode(%#v) failed with %v; want success", fixt.data, err) - } - - if got, want := buf.String(), fixt.json+"\n"; got != want { - t.Errorf("got = %q; want %q; data = %#v", got, want, fixt.data) - } - } -} - -func TestJSONBuiltinDecoder(t *testing.T) { - var ( - m runtime.JSONBuiltin - got = new(examplepb.SimpleMessage) - - data = `{"id": "foo"}` - ) - r := strings.NewReader(data) - dec := m.NewDecoder(r) - if err := dec.Decode(got); err != nil { - t.Errorf("m.Unmarshal(got) failed with %v; want success", err) - } - - want := &examplepb.SimpleMessage{ - Id: "foo", - } - if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { - t.Errorf("got = %v; want = %v", got, want) - } -} - -func TestJSONBuiltinDecoderFields(t *testing.T) { - var m runtime.JSONBuiltin - for _, fixt := range builtinFieldFixtures { - r := strings.NewReader(fixt.json) - dec := m.NewDecoder(r) - dest := alloc(reflect.TypeOf(fixt.data)) - if err := dec.Decode(dest.Interface()); err != nil { - t.Errorf("dec.Decode(dest) failed with %v; want success; data = %q", err, fixt.json) - } - - got, want := dest.Elem().Interface(), fixt.data - if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { - t.Error(diff) - } - } -} - -var ( - builtinFieldFixtures = []struct { - data interface{} - json string - }{ - {data: "", json: `""`}, - {data: proto.String(""), json: `""`}, - {data: "foo", json: `"foo"`}, - {data: proto.String("foo"), json: `"foo"`}, - {data: int32(-1), json: "-1"}, - {data: proto.Int32(-1), json: "-1"}, - {data: int64(-1), json: "-1"}, - {data: proto.Int64(-1), json: "-1"}, - {data: uint32(123), json: "123"}, - {data: proto.Uint32(123), json: "123"}, - {data: uint64(123), json: "123"}, - {data: proto.Uint64(123), json: "123"}, - {data: float32(-1.5), json: "-1.5"}, - {data: proto.Float32(-1.5), json: "-1.5"}, - {data: float64(-1.5), json: "-1.5"}, - {data: proto.Float64(-1.5), json: "-1.5"}, - {data: true, json: "true"}, - {data: proto.Bool(true), json: "true"}, - {data: (*string)(nil), json: "null"}, - {data: new(emptypb.Empty), json: "{}"}, - {data: examplepb.NumericEnum_ONE, json: "1"}, - {data: nil, json: "null"}, - {data: (*string)(nil), json: "null"}, - {data: []interface{}{nil, "foo", -1.0, 1.234, true}, json: `[null,"foo",-1,1.234,true]`}, - { - data: map[string]interface{}{"bar": nil, "baz": -1.0, "fiz": 1.234, "foo": true}, - json: `{"bar":null,"baz":-1,"fiz":1.234,"foo":true}`, - }, - { - data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))), - json: "1", - }, - } - builtinKnownErrors = []struct { - data interface{} - json string - }{ - {data: examplepb.NumericEnum_ONE, json: "ONE"}, - { - data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))), - json: "ONE", - }, - { - data: &examplepb.ABitOfEverything_OneofString{OneofString: "abc"}, - json: `"abc"`, - }, - { - data: ×tamppb.Timestamp{ - Seconds: 1462875553, - Nanos: 123000000, - }, - json: `"2016-05-10T10:19:13.123Z"`, - }, - { - data: &wrapperspb.Int32Value{Value: 123}, - json: "123", - }, - } -) diff --git a/gateway/runtime/marshal_jsonpb.go b/gateway/runtime/marshal_jsonpb.go index 38ac3dd..7387c8e 100644 --- a/gateway/runtime/marshal_jsonpb.go +++ b/gateway/runtime/marshal_jsonpb.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "reflect" + "strconv" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" @@ -113,6 +114,36 @@ func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) { return buf.Bytes(), nil } + + if rv.Type().Elem().Implements(typeProtoEnum) { + var buf bytes.Buffer + err := buf.WriteByte('[') + if err != nil { + return nil, err + } + for i := 0; i < rv.Len(); i++ { + if i != 0 { + err = buf.WriteByte(',') + if err != nil { + return nil, err + } + } + if j.UseEnumNumbers { + _, err = buf.WriteString(strconv.FormatInt(rv.Index(i).Int(), 10)) + } else { + _, err = buf.WriteString("\"" + rv.Index(i).Interface().(protoEnum).String() + "\"") + } + if err != nil { + return nil, err + } + } + err = buf.WriteByte(']') + if err != nil { + return nil, err + } + + return buf.Bytes(), nil + } } if rv.Kind() == reflect.Map { @@ -237,6 +268,10 @@ func decodeNonProtoField(d *json.Decoder, unmarshaler protojson.UnmarshalOptions } bk := result[0] bv := reflect.New(rv.Type().Elem()) + if v == nil { + null := json.RawMessage("null") + v = &null + } if err := unmarshalJSONPb([]byte(*v), unmarshaler, bv.Interface()); err != nil { return err } @@ -285,6 +320,8 @@ type protoEnum interface { EnumDescriptor() ([]byte, []int) } +var typeProtoEnum = reflect.TypeOf((*protoEnum)(nil)).Elem() + var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem() // Delimiter for newline encoded JSON streams. diff --git a/gateway/runtime/marshal_jsonpb_test.go b/gateway/runtime/marshal_jsonpb_test.go deleted file mode 100644 index e508562..0000000 --- a/gateway/runtime/marshal_jsonpb_test.go +++ /dev/null @@ -1,877 +0,0 @@ -package runtime_test - -import ( - "bytes" - "reflect" - "strconv" - "strings" - "testing" - - durationpb "github.com/golang/protobuf/ptypes/duration" - emptypb "github.com/golang/protobuf/ptypes/empty" - structpb "github.com/golang/protobuf/ptypes/struct" - timestamppb "github.com/golang/protobuf/ptypes/timestamp" - wrapperspb "github.com/golang/protobuf/ptypes/wrappers" - "github.com/google/go-cmp/cmp" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" - "google.golang.org/protobuf/encoding/protojson" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/testing/protocmp" -) - -func TestJSONPbMarshal(t *testing.T) { - msg := examplepb.ABitOfEverything{ - SingleNested: &examplepb.ABitOfEverything_Nested{}, - RepeatedStringValue: []string{}, - MappedStringValue: map[string]string{}, - MappedNestedValue: map[string]*examplepb.ABitOfEverything_Nested{}, - RepeatedEnumValue: []examplepb.NumericEnum{}, - TimestampValue: ×tamppb.Timestamp{}, - Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - Nested: []*examplepb.ABitOfEverything_Nested{ - { - Name: "foo", - Amount: 12345, - }, - }, - Uint64Value: 0xFFFFFFFFFFFFFFFF, - EnumValue: examplepb.NumericEnum_ONE, - OneofValue: &examplepb.ABitOfEverything_OneofString{ - OneofString: "bar", - }, - MapValue: map[string]examplepb.NumericEnum{ - "a": examplepb.NumericEnum_ONE, - "b": examplepb.NumericEnum_ZERO, - }, - RepeatedEnumAnnotation: []examplepb.NumericEnum{}, - EnumValueAnnotation: examplepb.NumericEnum_ONE, - RepeatedStringAnnotation: []string{}, - RepeatedNestedAnnotation: []*examplepb.ABitOfEverything_Nested{}, - NestedAnnotation: &examplepb.ABitOfEverything_Nested{}, - } - - for i, spec := range []struct { - useEnumNumbers, emitUnpopulated bool - indent string - useProtoNames bool - verifier func(json string) - }{ - { - verifier: func(json string) { - if !strings.Contains(json, "ONE") { - t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json) - } - if want := "uint64Value"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - useEnumNumbers: true, - verifier: func(json string) { - if strings.Contains(json, "ONE") { - t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json) - } - }, - }, - { - emitUnpopulated: true, - verifier: func(json string) { - if want := `"sfixed32Value"`; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - indent: "\t\t", - verifier: func(json string) { - if want := "\t\t\"amount\":"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - useProtoNames: true, - verifier: func(json string) { - if want := "uint64_value"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - } { - t.Run(strconv.Itoa(i), func(t *testing.T) { - m := runtime.JSONPb{ - MarshalOptions: protojson.MarshalOptions{ - EmitUnpopulated: spec.emitUnpopulated, - Indent: spec.indent, - UseProtoNames: spec.useProtoNames, - UseEnumNumbers: spec.useEnumNumbers, - }, - } - buf, err := m.Marshal(&msg) - if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", &msg, err, spec) - } - - var got examplepb.ABitOfEverything - unmarshaler := &protojson.UnmarshalOptions{} - if err = unmarshaler.Unmarshal(buf, &got); err != nil { - t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", string(buf), err, spec) - } - if diff := cmp.Diff(&got, &msg, protocmp.Transform()); diff != "" { - t.Errorf("case %d: spec=%v; %s", i, spec, diff) - } - if spec.verifier != nil { - spec.verifier(string(buf)) - } - }) - } -} - -func TestJSONPbMarshalFields(t *testing.T) { - var m runtime.JSONPb - m.UseEnumNumbers = true // builtin fixtures include an enum, expected to be marshaled as int - for _, spec := range builtinFieldFixtures { - buf, err := m.Marshal(spec.data) - if err != nil { - t.Errorf("m.Marshal(%#v) failed with %v; want success", spec.data, err) - } - if got, want := string(buf), spec.json; got != want { - t.Errorf("m.Marshal(%#v) = %q; want %q", spec.data, got, want) - } - } - - m.UseEnumNumbers = false - buf, err := m.Marshal(examplepb.NumericEnum_ONE) - if err != nil { - t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err) - } - if got, want := string(buf), `"ONE"`; got != want { - t.Errorf("m.Marshal(%#v) = %q; want %q", examplepb.NumericEnum_ONE, got, want) - } -} - -func TestJSONPbUnmarshal(t *testing.T) { - var ( - m runtime.JSONPb - got examplepb.ABitOfEverything - ) - for i, data := range []string{ - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": 18446744073709551615, - "enumValue": "ONE", - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": "18446744073709551615", - "enumValue": "ONE", - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": 18446744073709551615, - "enumValue": 1, - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - } { - if err := m.Unmarshal([]byte(data), &got); err != nil { - t.Errorf("case %d: m.Unmarshal(%q, &got) failed with %v; want success", i, data, err) - } - - want := examplepb.ABitOfEverything{ - Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - Nested: []*examplepb.ABitOfEverything_Nested{ - { - Name: "foo", - Amount: 12345, - }, - }, - Uint64Value: 0xFFFFFFFFFFFFFFFF, - EnumValue: examplepb.NumericEnum_ONE, - OneofValue: &examplepb.ABitOfEverything_OneofString{ - OneofString: "bar", - }, - MapValue: map[string]examplepb.NumericEnum{ - "a": examplepb.NumericEnum_ONE, - "b": examplepb.NumericEnum_ZERO, - }, - } - - if diff := cmp.Diff(&got, &want, protocmp.Transform()); diff != "" { - t.Errorf("case %d: %s", i, diff) - } - } -} - -func TestJSONPbUnmarshalFields(t *testing.T) { - var m runtime.JSONPb - for _, fixt := range fieldFixtures { - if fixt.skipUnmarshal { - continue - } - - dest := reflect.New(reflect.TypeOf(fixt.data)) - if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err != nil { - t.Errorf("m.Unmarshal(%q, %T) failed with %v; want success", fixt.json, dest.Interface(), err) - } - if diff := cmp.Diff(dest.Elem().Interface(), fixt.data, protocmp.Transform()); diff != "" { - t.Errorf("dest = %#v; want %#v; input = %v", dest.Elem().Interface(), fixt.data, fixt.json) - } - } -} - -func TestJSONPbEncoder(t *testing.T) { - msg := examplepb.ABitOfEverything{ - SingleNested: &examplepb.ABitOfEverything_Nested{}, - RepeatedStringValue: []string{}, - MappedStringValue: map[string]string{}, - MappedNestedValue: map[string]*examplepb.ABitOfEverything_Nested{}, - RepeatedEnumValue: []examplepb.NumericEnum{}, - TimestampValue: ×tamppb.Timestamp{}, - Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - Nested: []*examplepb.ABitOfEverything_Nested{ - { - Name: "foo", - Amount: 12345, - }, - }, - Uint64Value: 0xFFFFFFFFFFFFFFFF, - OneofValue: &examplepb.ABitOfEverything_OneofString{ - OneofString: "bar", - }, - MapValue: map[string]examplepb.NumericEnum{ - "a": examplepb.NumericEnum_ONE, - "b": examplepb.NumericEnum_ZERO, - }, - RepeatedEnumAnnotation: []examplepb.NumericEnum{}, - EnumValueAnnotation: examplepb.NumericEnum_ONE, - RepeatedStringAnnotation: []string{}, - RepeatedNestedAnnotation: []*examplepb.ABitOfEverything_Nested{}, - NestedAnnotation: &examplepb.ABitOfEverything_Nested{}, - } - - for i, spec := range []struct { - useEnumNumbers, emitUnpopulated bool - indent string - useProtoNames bool - verifier func(json string) - }{ - { - verifier: func(json string) { - if !strings.Contains(json, "ONE") { - t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json) - } - if want := "uint64Value"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - useEnumNumbers: true, - verifier: func(json string) { - if strings.Contains(json, "ONE") { - t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json) - } - }, - }, - { - emitUnpopulated: true, - verifier: func(json string) { - if want := `"sfixed32Value"`; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - indent: "\t\t", - verifier: func(json string) { - if want := "\t\t\"amount\":"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - { - useProtoNames: true, - verifier: func(json string) { - if want := "uint64_value"; !strings.Contains(json, want) { - t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want) - } - }, - }, - } { - m := runtime.JSONPb{ - MarshalOptions: protojson.MarshalOptions{ - EmitUnpopulated: spec.emitUnpopulated, - Indent: spec.indent, - UseProtoNames: spec.useProtoNames, - UseEnumNumbers: spec.useEnumNumbers, - }, - } - - var buf bytes.Buffer - enc := m.NewEncoder(&buf) - if err := enc.Encode(&msg); err != nil { - t.Errorf("enc.Encode(%v) failed with %v; want success; spec=%v", &msg, err, spec) - } - - var got examplepb.ABitOfEverything - unmarshaler := &protojson.UnmarshalOptions{} - if err := unmarshaler.Unmarshal(buf.Bytes(), &got); err != nil { - t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", buf.String(), err, spec) - } - if diff := cmp.Diff(&got, &msg, protocmp.Transform()); diff != "" { - t.Errorf("case %d: %s", i, diff) - } - if spec.verifier != nil { - spec.verifier(buf.String()) - } - } -} - -func TestJSONPbEncoderFields(t *testing.T) { - var m runtime.JSONPb - for _, fixt := range fieldFixtures { - var buf bytes.Buffer - enc := m.NewEncoder(&buf) - if err := enc.Encode(fixt.data); err != nil { - t.Errorf("enc.Encode(%#v) failed with %v; want success", fixt.data, err) - } - if got, want := buf.String(), fixt.json+string(m.Delimiter()); got != want { - t.Errorf("enc.Encode(%#v) = %q; want %q", fixt.data, got, want) - } - } - - m.UseEnumNumbers = true - buf, err := m.Marshal(examplepb.NumericEnum_ONE) - if err != nil { - t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err) - } - if got, want := string(buf), "1"; got != want { - t.Errorf("m.Marshal(%#v) = %q; want %q", examplepb.NumericEnum_ONE, got, want) - } -} - -func TestJSONPbDecoder(t *testing.T) { - var ( - m runtime.JSONPb - got examplepb.ABitOfEverything - ) - for _, data := range []string{ - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": 18446744073709551615, - "enumValue": "ONE", - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": "18446744073709551615", - "enumValue": "ONE", - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "nested": [ - {"name": "foo", "amount": 12345} - ], - "uint64Value": 18446744073709551615, - "enumValue": 1, - "oneofString": "bar", - "mapValue": { - "a": 1, - "b": 0 - } - }`, - } { - r := strings.NewReader(data) - dec := m.NewDecoder(r) - if err := dec.Decode(&got); err != nil { - t.Errorf("m.Unmarshal(&got) failed with %v; want success; data=%q", err, data) - } - - want := examplepb.ABitOfEverything{ - Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - Nested: []*examplepb.ABitOfEverything_Nested{ - { - Name: "foo", - Amount: 12345, - }, - }, - Uint64Value: 0xFFFFFFFFFFFFFFFF, - EnumValue: examplepb.NumericEnum_ONE, - OneofValue: &examplepb.ABitOfEverything_OneofString{ - OneofString: "bar", - }, - MapValue: map[string]examplepb.NumericEnum{ - "a": examplepb.NumericEnum_ONE, - "b": examplepb.NumericEnum_ZERO, - }, - } - if diff := cmp.Diff(&got, &want, protocmp.Transform()); diff != "" { - t.Errorf("data %q: %s", data, diff) - } - } -} - -func TestJSONPbDecoderFields(t *testing.T) { - var m runtime.JSONPb - for _, fixt := range fieldFixtures { - if fixt.skipUnmarshal { - continue - } - - dest := reflect.New(reflect.TypeOf(fixt.data)) - dec := m.NewDecoder(strings.NewReader(fixt.json)) - if err := dec.Decode(dest.Interface()); err != nil { - t.Errorf("dec.Decode(%T) failed with %v; want success; input = %q", dest.Interface(), err, fixt.json) - } - if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) { - t.Errorf("dest = %#v; want %#v; input = %v", got, want, fixt.json) - } - } -} - -func TestJSONPbDecoderUnknownField(t *testing.T) { - var ( - m = runtime.JSONPb{ - UnmarshalOptions: protojson.UnmarshalOptions{ - DiscardUnknown: false, - }, - } - got examplepb.ABitOfEverything - ) - data := `{ - "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - "unknownField": "111" - }` - - r := strings.NewReader(data) - dec := m.NewDecoder(r) - if err := dec.Decode(&got); err == nil { - t.Errorf("m.Unmarshal(&got) not failed; want `unknown field` error; data=%q", data) - } -} - -var ( - fieldFixtures = []struct { - data interface{} - json string - skipUnmarshal bool - }{ - {data: int32(1), json: "1"}, - {data: proto.Int32(1), json: "1"}, - {data: int64(1), json: "1"}, - {data: proto.Int64(1), json: "1"}, - {data: uint32(1), json: "1"}, - {data: proto.Uint32(1), json: "1"}, - {data: uint64(1), json: "1"}, - {data: proto.Uint64(1), json: "1"}, - {data: "abc", json: `"abc"`}, - {data: proto.String("abc"), json: `"abc"`}, - {data: float32(1.5), json: "1.5"}, - {data: proto.Float32(1.5), json: "1.5"}, - {data: float64(1.5), json: "1.5"}, - {data: proto.Float64(1.5), json: "1.5"}, - {data: true, json: "true"}, - {data: false, json: "false"}, - {data: (*string)(nil), json: "null"}, - { - data: examplepb.NumericEnum_ONE, - json: `"ONE"`, - // TODO(yugui) support unmarshaling of symbolic enum - skipUnmarshal: true, - }, - { - data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))), - json: `"ONE"`, - // TODO(yugui) support unmarshaling of symbolic enum - skipUnmarshal: true, - }, - - { - data: map[string]int32{ - "foo": 1, - }, - json: `{"foo":1}`, - }, - { - data: map[string]*examplepb.SimpleMessage{ - "foo": {Id: "bar"}, - }, - json: `{"foo":{"id":"bar"}}`, - }, - { - data: map[int32]*examplepb.SimpleMessage{ - 1: {Id: "foo"}, - }, - json: `{"1":{"id":"foo"}}`, - }, - { - data: map[bool]*examplepb.SimpleMessage{ - true: {Id: "foo"}, - }, - json: `{"true":{"id":"foo"}}`, - }, - { - data: &durationpb.Duration{ - Seconds: 123, - Nanos: 456000000, - }, - json: `"123.456s"`, - }, - { - data: ×tamppb.Timestamp{ - Seconds: 1462875553, - Nanos: 123000000, - }, - json: `"2016-05-10T10:19:13.123Z"`, - }, - { - data: new(emptypb.Empty), - json: "{}", - }, - { - data: &structpb.Value{ - Kind: new(structpb.Value_NullValue), - }, - json: "null", - skipUnmarshal: true, - }, - { - data: &structpb.Value{ - Kind: &structpb.Value_NumberValue{ - NumberValue: 123.4, - }, - }, - json: "123.4", - skipUnmarshal: true, - }, - { - data: &structpb.Value{ - Kind: &structpb.Value_StringValue{ - StringValue: "abc", - }, - }, - json: `"abc"`, - skipUnmarshal: true, - }, - { - data: &structpb.Value{ - Kind: &structpb.Value_BoolValue{ - BoolValue: true, - }, - }, - json: "true", - skipUnmarshal: true, - }, - { - data: &structpb.Struct{ - Fields: map[string]*structpb.Value{ - "foo_bar": { - Kind: &structpb.Value_BoolValue{ - BoolValue: true, - }, - }, - }, - }, - json: `{"foo_bar":true}`, - skipUnmarshal: true, - }, - - { - data: &wrapperspb.BoolValue{Value: true}, - json: "true", - }, - { - data: &wrapperspb.DoubleValue{Value: 123.456}, - json: "123.456", - }, - { - data: &wrapperspb.FloatValue{Value: 123.456}, - json: "123.456", - }, - { - data: &wrapperspb.Int32Value{Value: -123}, - json: "-123", - }, - { - data: &wrapperspb.Int64Value{Value: -123}, - json: `"-123"`, - }, - { - data: &wrapperspb.UInt32Value{Value: 123}, - json: "123", - }, - { - data: &wrapperspb.UInt64Value{Value: 123}, - json: `"123"`, - }, - // TODO(yugui) Add other well-known types once jsonpb supports them - } -) - -func TestJSONPbMarshalResponseBodies(t *testing.T) { - marshaler := &runtime.JSONPb{} - for i, spec := range []struct { - input interface{} - emitUnpopulated bool - verifier func(*testing.T, interface{}, []byte) - }{ - { - input: &examplepb.ResponseBodyOut{ - Response: &examplepb.ResponseBodyOut_Response{Data: "abcdef"}, - }, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out examplepb.ResponseBodyOut - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, &out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - emitUnpopulated: true, - input: &examplepb.ResponseBodyOut{}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out examplepb.ResponseBodyOut - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, &out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: &examplepb.RepeatedResponseBodyOut_Response{}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, &out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - emitUnpopulated: true, - input: &examplepb.RepeatedResponseBodyOut_Response{}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, &out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil), - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []*examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - emitUnpopulated: true, - input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil), - verifier: func(t *testing.T, _ interface{}, json []byte) { - var out []*examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff([]*examplepb.RepeatedResponseBodyOut_Response{}, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: []*examplepb.RepeatedResponseBodyOut_Response{}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []*examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: []string{"something"}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []string - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: []string{}, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []string - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: ([]string)(nil), - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []string - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - emitUnpopulated: true, - input: ([]string)(nil), - verifier: func(t *testing.T, _ interface{}, json []byte) { - var out []string - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff([]string{}, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - input: []*examplepb.RepeatedResponseBodyOut_Response{ - {}, - { - Data: "abc", - Type: examplepb.RepeatedResponseBodyOut_Response_A, - }, - }, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []*examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - { - emitUnpopulated: true, - input: []*examplepb.RepeatedResponseBodyOut_Response{ - {}, - { - Data: "abc", - Type: examplepb.RepeatedResponseBodyOut_Response_B, - }, - }, - verifier: func(t *testing.T, input interface{}, json []byte) { - var out []*examplepb.RepeatedResponseBodyOut_Response - err := marshaler.Unmarshal(json, &out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - diff := cmp.Diff(input, out, protocmp.Transform()) - if diff != "" { - t.Errorf("json not equal:\n%s", diff) - } - }, - }, - } { - - t.Run(strconv.Itoa(i), func(t *testing.T) { - m := runtime.JSONPb{ - MarshalOptions: protojson.MarshalOptions{ - EmitUnpopulated: spec.emitUnpopulated, - }, - } - val := spec.input - buf, err := m.Marshal(val) - if err != nil { - t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", val, err, spec) - } - if spec.verifier != nil { - spec.verifier(t, spec.input, buf) - } - }) - } -} diff --git a/gateway/runtime/marshal_proto_test.go b/gateway/runtime/marshal_proto_test.go deleted file mode 100644 index df156ac..0000000 --- a/gateway/runtime/marshal_proto_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package runtime_test - -import ( - "bytes" - "testing" - - timestamppb "github.com/golang/protobuf/ptypes/timestamp" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" - "google.golang.org/protobuf/proto" -) - -var message = &examplepb.ABitOfEverything{ - SingleNested: &examplepb.ABitOfEverything_Nested{}, - RepeatedStringValue: nil, - MappedStringValue: nil, - MappedNestedValue: nil, - RepeatedEnumValue: nil, - TimestampValue: ×tamppb.Timestamp{}, - Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", - Nested: []*examplepb.ABitOfEverything_Nested{ - { - Name: "foo", - Amount: 12345, - }, - }, - Uint64Value: 0xFFFFFFFFFFFFFFFF, - EnumValue: examplepb.NumericEnum_ONE, - OneofValue: &examplepb.ABitOfEverything_OneofString{ - OneofString: "bar", - }, - MapValue: map[string]examplepb.NumericEnum{ - "a": examplepb.NumericEnum_ONE, - "b": examplepb.NumericEnum_ZERO, - }, -} - -func TestProtoMarshalUnmarshal(t *testing.T) { - marshaller := runtime.ProtoMarshaller{} - - // Marshal - buffer, err := marshaller.Marshal(message) - if err != nil { - t.Fatalf("Marshalling returned error: %s", err.Error()) - } - - // Unmarshal - unmarshalled := &examplepb.ABitOfEverything{} - err = marshaller.Unmarshal(buffer, unmarshalled) - if err != nil { - t.Fatalf("Unmarshalling returned error: %s", err.Error()) - } - - if !proto.Equal(unmarshalled, message) { - t.Errorf( - "Unmarshalled didn't match original message: (original = %v) != (unmarshalled = %v)", - unmarshalled, - message, - ) - } -} - -func TestProtoEncoderDecodert(t *testing.T) { - marshaller := runtime.ProtoMarshaller{} - - var buf bytes.Buffer - - encoder := marshaller.NewEncoder(&buf) - decoder := marshaller.NewDecoder(&buf) - - // Encode - err := encoder.Encode(message) - if err != nil { - t.Fatalf("Encoding returned error: %s", err.Error()) - } - - // Decode - unencoded := &examplepb.ABitOfEverything{} - err = decoder.Decode(unencoded) - if err != nil { - t.Fatalf("Unmarshalling returned error: %s", err.Error()) - } - - if !proto.Equal(unencoded, message) { - t.Errorf( - "Unencoded didn't match original message: (original = %v) != (unencoded = %v)", - unencoded, - message, - ) - } -} diff --git a/gateway/runtime/mux.go b/gateway/runtime/mux.go index 289bcca..fa8e9bf 100644 --- a/gateway/runtime/mux.go +++ b/gateway/runtime/mux.go @@ -2,20 +2,53 @@ package runtime import ( "context" + "errors" "fmt" "net/http" "net/textproto" + "regexp" "strings" - + "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" - + "github.com/binchencoder/gateway-proto/data" ) +// UnescapingMode defines the behavior of ServeMux when unescaping path parameters. +type UnescapingMode int + +const ( + // UnescapingModeLegacy is the default V2 behavior, which escapes the entire + // path string before doing any routing. + UnescapingModeLegacy UnescapingMode = iota + + // UnescapingModeAllExceptReserved unescapes all path parameters except RFC 6570 + // reserved characters. + UnescapingModeAllExceptReserved + + // UnescapingModeAllExceptSlash unescapes URL path parameters except path + // separators, which will be left as "%2F". + UnescapingModeAllExceptSlash + + // UnescapingModeAllCharacters unescapes all URL path parameters. + UnescapingModeAllCharacters + + // UnescapingModeDefault is the default escaping type. + // TODO(v3): default this to UnescapingModeAllExceptReserved per grpc-httpjson-transcoding's + // reference implementation + UnescapingModeDefault = UnescapingModeLegacy +) + +var ( + encodedPathSplitter = regexp.MustCompile("(/|%2F)") +) + // A HandlerFunc handles a specific pair of path pattern and HTTP method. type HandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, pathParams map[string]string) @@ -33,6 +66,7 @@ type ServeMux struct { streamErrorHandler StreamErrorHandlerFunc routingErrorHandler RoutingErrorHandlerFunc disablePathLengthFallback bool + unescapingMode UnescapingMode } // ServeMuxOption is an option that can be given to a ServeMux on construction. @@ -50,6 +84,14 @@ func WithForwardResponseOption(forwardResponseOption func(context.Context, http. } } +// WithEscapingType sets the escaping type. See the definitions of UnescapingMode +// for more information. +func WithUnescapingMode(mode UnescapingMode) ServeMuxOption { + return func(serveMux *ServeMux) { + serveMux.unescapingMode = mode + } +} + // SetQueryParameterParser sets the query parameter parser, used to populate message from query parameters. // Configuring this will mean the generated OpenAPI output is no longer correct, and it should be // done with careful consideration. @@ -80,11 +122,30 @@ func DefaultHeaderMatcher(key string) (string, bool) { // This matcher will be called with each header in http.Request. If matcher returns true, that header will be // passed to gRPC context. To transform the header before passing to gRPC context, matcher should return modified header. func WithIncomingHeaderMatcher(fn HeaderMatcherFunc) ServeMuxOption { + for _, header := range fn.matchedMalformedHeaders() { + grpclog.Warningf("The configured forwarding filter would allow %q to be sent to the gRPC server, which will likely cause errors. See https://github.com/grpc/grpc-go/pull/4803#issuecomment-986093310 for more information.", header) + } + return func(mux *ServeMux) { mux.incomingHeaderMatcher = fn } } +// matchedMalformedHeaders returns the malformed headers that would be forwarded to gRPC server. +func (fn HeaderMatcherFunc) matchedMalformedHeaders() []string { + if fn == nil { + return nil + } + headers := make([]string, 0) + for header := range malformedHTTPHeaders { + out, accept := fn(header) + if accept && isMalformedHTTPHeader(out) { + headers = append(headers, out) + } + } + return headers +} + // WithOutgoingHeaderMatcher returns a ServeMuxOption representing a headerMatcher for outgoing response from gateway. // // This matcher will be called with each header in response header metadata. If matcher returns true, that header will be @@ -146,6 +207,55 @@ func WithDisablePathLengthFallback() ServeMuxOption { } } +// WithHealthEndpointAt returns a ServeMuxOption that will add an endpoint to the created ServeMux at the path specified by endpointPath. +// When called the handler will forward the request to the upstream grpc service health check (defined in the +// gRPC Health Checking Protocol). +// +// See here https://grpc-ecosystem.github.io/grpc-gateway/docs/operations/health_check/ for more information on how +// to setup the protocol in the grpc server. +// +// If you define a service as query parameter, this will also be forwarded as service in the HealthCheckRequest. +func WithHealthEndpointAt(healthCheckClient grpc_health_v1.HealthClient, endpointPath string, sid data.ServiceId) ServeMuxOption { + return func(s *ServeMux) { + // error can be ignored since pattern is definitely valid + _ = s.HandlePath( + http.MethodGet, endpointPath, sid, func(ctx context.Context, w http.ResponseWriter, r *http.Request, _ map[string]string, + ) { + _, outboundMarshaler := MarshalerForRequest(s, r) + + resp, err := healthCheckClient.Check(r.Context(), &grpc_health_v1.HealthCheckRequest{ + Service: r.URL.Query().Get("service"), + }) + if err != nil { + s.errorHandler(r.Context(), s, outboundMarshaler, w, r, err) + return + } + + if resp.GetStatus() != grpc_health_v1.HealthCheckResponse_SERVING { + var err error + switch resp.GetStatus() { + case grpc_health_v1.HealthCheckResponse_NOT_SERVING, grpc_health_v1.HealthCheckResponse_UNKNOWN: + err = status.Error(codes.Unavailable, resp.String()) + case grpc_health_v1.HealthCheckResponse_SERVICE_UNKNOWN: + err = status.Error(codes.NotFound, resp.String()) + } + + s.errorHandler(r.Context(), s, outboundMarshaler, w, r, err) + return + } + + _ = outboundMarshaler.NewEncoder(w).Encode(resp) + }) + } +} + +// WithHealthzEndpoint returns a ServeMuxOption that will add a /healthz endpoint to the created ServeMux. +// +// See WithHealthEndpointAt for the general implementation. +func WithHealthzEndpoint(healthCheckClient grpc_health_v1.HealthClient, sid data.ServiceId) ServeMuxOption { + return WithHealthEndpointAt(healthCheckClient, "/healthz", sid) +} + // NewServeMux returns a new ServeMux whose internal mapping is empty. func NewServeMux(opts ...ServeMuxOption) *ServeMux { serveMux := &ServeMux{ @@ -155,6 +265,7 @@ func NewServeMux(opts ...ServeMuxOption) *ServeMux { errorHandler: DefaultHTTPErrorHandler, streamErrorHandler: DefaultStreamErrorHandler, routingErrorHandler: DefaultRoutingErrorHandler, + unescapingMode: UnescapingModeDefault, } for _, opt := range opts { @@ -180,7 +291,7 @@ func (s *ServeMux) Handle(meth string, pat Pattern, sid data.ServiceId, h Handle } // HandlePath allows users to configure custom path handlers. -// refer: https://grpc-ecosystem.github.io/grpc-gateway/docs/inject_router.html +// refer: https://grpc-ecosystem.github.io/grpc-gateway/docs/operations/inject_router/ func (s *ServeMux) HandlePath(meth string, pathPattern string, sid data.ServiceId, h HandlerFunc) error { compiler, err := httprule.Parse(pathPattern) if err != nil { @@ -195,7 +306,7 @@ func (s *ServeMux) HandlePath(meth string, pathPattern string, sid data.ServiceI return nil } -// ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.Path. +// ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.URL.Path. func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx, err := RequestReceived(w, r) if err != nil { @@ -210,18 +321,20 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - components := strings.Split(path[1:], "/") - l := len(components) - var verb string - idx := strings.LastIndex(components[l-1], ":") - if idx == 0 { - _, outboundMarshaler := MarshalerForRequest(s, r) - s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusNotFound) - return + // TODO(v3): remove UnescapingModeLegacy + if s.unescapingMode != UnescapingModeLegacy && r.URL.RawPath != "" { + path = r.URL.RawPath } - if idx > 0 { - c := components[l-1] - components[l-1], verb = c[:idx], c[idx+1:] + + var components []string + // since in UnescapeModeLegacy, the URL will already have been fully unescaped, if we also split on "%2F" + // in this escaping mode we would be double unescaping but in UnescapingModeAllCharacters, we still do as the + // path is the RawPath (i.e. unescaped). That does mean that the behavior of this function will change its default + // behavior when the UnescapingModeDefault gets changed from UnescapingModeLegacy to UnescapingModeAllExceptReserved + if s.unescapingMode == UnescapingModeAllCharacters { + components = encodedPathSplitter.Split(path[1:], -1) + } else { + components = strings.Split(path[1:], "/") } if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && s.isPathLengthFallback(r) { @@ -233,9 +346,45 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } } + + // Verb out here is to memoize for the fallback case below + var verb string + for _, h := range s.handlers[r.Method] { - pathParams, err := h.pat.Match(components, verb) + // If the pattern has a verb, explicitly look for a suffix in the last + // component that matches a colon plus the verb. This allows us to + // handle some cases that otherwise can't be correctly handled by the + // former LastIndex case, such as when the verb literal itself contains + // a colon. This should work for all cases that have run through the + // parser because we know what verb we're looking for, however, there + // are still some cases that the parser itself cannot disambiguate. See + // the comment there if interested. + patVerb := h.pat.Verb() + l := len(components) + lastComponent := components[l-1] + var idx int = -1 + if patVerb != "" && strings.HasSuffix(lastComponent, ":"+patVerb) { + idx = len(lastComponent) - len(patVerb) - 1 + } + if idx == 0 { + _, outboundMarshaler := MarshalerForRequest(s, r) + s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusNotFound) + return + } + if idx > 0 { + components[l-1], verb = lastComponent[:idx], lastComponent[idx+1:] + } + + pathParams, err := h.pat.MatchAndEscape(components, verb, s.unescapingMode) if err != nil { + var mse MalformedSequenceError + if ok := errors.As(err, &mse); ok { + _, outboundMarshaler := MarshalerForRequest(s, r) + s.errorHandler(ctx, s, outboundMarshaler, w, r, &HTTPStatusError{ + HTTPStatus: http.StatusBadRequest, + Err: mse, + }) + } continue } h.h(ctx, w, r, pathParams) @@ -249,8 +398,16 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { continue } for _, h := range handlers { - pathParams, err := h.pat.Match(components, verb) + pathParams, err := h.pat.MatchAndEscape(components, verb, s.unescapingMode) if err != nil { + var mse MalformedSequenceError + if ok := errors.As(err, &mse); ok { + _, outboundMarshaler := MarshalerForRequest(s, r) + s.errorHandler(ctx, s, outboundMarshaler, w, r, &HTTPStatusError{ + HTTPStatus: http.StatusBadRequest, + Err: mse, + }) + } continue } // X-HTTP-Method-Override is optional. Always allow fallback to POST. diff --git a/gateway/runtime/mux_test.go b/gateway/runtime/mux_test.go index b73be95..96d0836 100644 --- a/gateway/runtime/mux_test.go +++ b/gateway/runtime/mux_test.go @@ -6,12 +6,18 @@ import ( "fmt" "net/http" "net/http/httptest" + "net/url" "strconv" + "strings" "testing" // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/binchencoder/ease-gateway/gateway/runtime" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/health/grpc_health_v1" + "google.golang.org/grpc/status" ) func TestMuxServeHTTP(t *testing.T) { @@ -32,6 +38,7 @@ func TestMuxServeHTTP(t *testing.T) { respContent string disablePathLengthFallback bool + unescapingMode runtime.UnescapingMode }{ { patterns: nil, @@ -310,11 +317,163 @@ func TestMuxServeHTTP(t *testing.T) { }, respStatus: http.StatusBadRequest, }, + { + patterns: []stubPattern{ + { + method: "POST", + ops: []int{int(utilities.OpLitPush), 0, int(utilities.OpPush), 0, int(utilities.OpConcatN), 1, int(utilities.OpCapture), 1}, + pool: []string{"foo", "id"}, + }, + { + method: "POST", + ops: []int{int(utilities.OpLitPush), 0, int(utilities.OpPush), 0, int(utilities.OpConcatN), 1, int(utilities.OpCapture), 1}, + pool: []string{"foo", "id"}, + verb: "verb:subverb", + }, + }, + reqMethod: "POST", + reqPath: "/foo/bar:verb:subverb", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusOK, + respContent: "POST /foo/{id=*}:verb:subverb", + }, + { + patterns: []stubPattern{ + { + method: "GET", + ops: []int{int(utilities.OpLitPush), 0, int(utilities.OpPush), 1, int(utilities.OpCapture), 1, int(utilities.OpLitPush), 2}, + pool: []string{"foo", "id", "bar"}, + }, + }, + reqMethod: "POST", + reqPath: "/foo/404%2fwith%2Fspace/bar", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusNotFound, + unescapingMode: runtime.UnescapingModeLegacy, + }, + { + patterns: []stubPattern{ + { + method: "GET", + ops: []int{ + int(utilities.OpLitPush), 0, + int(utilities.OpPush), 0, + int(utilities.OpConcatN), 1, + int(utilities.OpCapture), 1, + int(utilities.OpLitPush), 2}, + pool: []string{"foo", "id", "bar"}, + }, + }, + reqMethod: "GET", + reqPath: "/foo/success%2fwith%2Fspace/bar", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusOK, + unescapingMode: runtime.UnescapingModeAllExceptReserved, + respContent: "GET /foo/{id=*}/bar", + }, + { + patterns: []stubPattern{ + { + method: "GET", + ops: []int{ + int(utilities.OpLitPush), 0, + int(utilities.OpPush), 0, + int(utilities.OpConcatN), 1, + int(utilities.OpCapture), 1, + int(utilities.OpLitPush), 2}, + pool: []string{"foo", "id", "bar"}, + }, + }, + reqMethod: "GET", + reqPath: "/foo/success%2fwith%2Fspace/bar", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusNotFound, + unescapingMode: runtime.UnescapingModeAllCharacters, + }, + { + patterns: []stubPattern{ + { + method: "GET", + ops: []int{ + int(utilities.OpLitPush), 0, + int(utilities.OpPush), 0, + int(utilities.OpConcatN), 1, + int(utilities.OpCapture), 1, + int(utilities.OpLitPush), 2}, + pool: []string{"foo", "id", "bar"}, + }, + }, + reqMethod: "GET", + reqPath: "/foo/success%2fwith%2Fspace/bar", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusNotFound, + unescapingMode: runtime.UnescapingModeLegacy, + }, + { + patterns: []stubPattern{ + { + method: "GET", + ops: []int{ + int(utilities.OpLitPush), 0, + int(utilities.OpPushM), 0, + int(utilities.OpConcatN), 1, + int(utilities.OpCapture), 1, + }, + pool: []string{"foo", "id", "bar"}, + }, + }, + reqMethod: "GET", + reqPath: "/foo/success%2fwith%2Fspace", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusOK, + unescapingMode: runtime.UnescapingModeAllExceptReserved, + respContent: "GET /foo/{id=**}", + }, + { + patterns: []stubPattern{ + { + method: "POST", + ops: []int{ + int(utilities.OpLitPush), 0, + int(utilities.OpLitPush), 1, + int(utilities.OpLitPush), 2, + int(utilities.OpPush), 0, + int(utilities.OpConcatN), 2, + int(utilities.OpCapture), 3, + }, + pool: []string{"api", "v1", "organizations", "name"}, + verb: "action", + }, + }, + reqMethod: "POST", + reqPath: "/api/v1/" + url.QueryEscape("organizations/foo") + ":action", + headers: map[string]string{ + "Content-Type": "application/json", + }, + respStatus: http.StatusOK, + unescapingMode: runtime.UnescapingModeAllCharacters, + respContent: "POST /api/v1/{name=organizations/*}:action", + }, } { t.Run(strconv.Itoa(i), func(t *testing.T) { var opts []runtime.ServeMuxOption + opts = append(opts, runtime.WithUnescapingMode(spec.unescapingMode)) if spec.disablePathLengthFallback { - opts = append(opts, runtime.WithDisablePathLengthFallback()) + opts = append(opts, + runtime.WithDisablePathLengthFallback(), + ) } mux := runtime.NewServeMux(opts...) for _, p := range spec.patterns { @@ -329,10 +488,10 @@ func TestMuxServeHTTP(t *testing.T) { }(p) } - url := fmt.Sprintf("http://host.example%s", spec.reqPath) - r, err := http.NewRequest(spec.reqMethod, url, bytes.NewReader(nil)) + reqUrl := fmt.Sprintf("https://host.example%s", spec.reqPath) + r, err := http.NewRequest(spec.reqMethod, reqUrl, bytes.NewReader(nil)) if err != nil { - t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", spec.reqMethod, url, err) + t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", spec.reqMethod, reqUrl, err) } for name, value := range spec.headers { r.Header.Set(name, value) @@ -398,6 +557,12 @@ var defaultRouteMatcherTests = []struct { path string valid bool }{ + { + "Test route /", + "GET", + "/", + true, + }, { "Simple Endpoint", "GET", @@ -439,5 +604,137 @@ func TestServeMux_HandlePath(t *testing.T) { } }) } +} -} \ No newline at end of file +var healthCheckTests = []struct { + name string + code codes.Code + status grpc_health_v1.HealthCheckResponse_ServingStatus + httpStatusCode int +}{ + { + "Test grpc error code", + codes.NotFound, + grpc_health_v1.HealthCheckResponse_UNKNOWN, + http.StatusNotFound, + }, + { + "Test HealthCheckResponse_SERVING", + codes.OK, + grpc_health_v1.HealthCheckResponse_SERVING, + http.StatusOK, + }, + { + "Test HealthCheckResponse_NOT_SERVING", + codes.OK, + grpc_health_v1.HealthCheckResponse_NOT_SERVING, + http.StatusServiceUnavailable, + }, + { + "Test HealthCheckResponse_UNKNOWN", + codes.OK, + grpc_health_v1.HealthCheckResponse_UNKNOWN, + http.StatusServiceUnavailable, + }, + { + "Test HealthCheckResponse_SERVICE_UNKNOWN", + codes.OK, + grpc_health_v1.HealthCheckResponse_SERVICE_UNKNOWN, + http.StatusNotFound, + }, +} + +func TestWithHealthzEndpoint_codes(t *testing.T) { + for _, tt := range healthCheckTests { + t.Run(tt.name, func(t *testing.T) { + mux := runtime.NewServeMux(runtime.WithHealthzEndpoint(&dummyHealthCheckClient{status: tt.status, code: tt.code}, 1 /* sid */)) + + r := httptest.NewRequest(http.MethodGet, "/healthz", nil) + rr := httptest.NewRecorder() + + mux.ServeHTTP(rr, r) + + if rr.Code != tt.httpStatusCode { + t.Errorf( + "result http status code for grpc code %q and status %q should be %d, got %d", + tt.code, tt.status, tt.httpStatusCode, rr.Code, + ) + } + }) + } +} + +func TestWithHealthEndpointAt_consistentWithHealthz(t *testing.T) { + const endpointPath = "/healthz" + + r := httptest.NewRequest(http.MethodGet, endpointPath, nil) + + for _, tt := range healthCheckTests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + client := &dummyHealthCheckClient{ + status: tt.status, + code: tt.code, + } + + w := httptest.NewRecorder() + + runtime.NewServeMux( + runtime.WithHealthEndpointAt(client, endpointPath), + ).ServeHTTP(w, r) + + refW := httptest.NewRecorder() + + runtime.NewServeMux( + runtime.WithHealthzEndpoint(client, 1 /* sid */), + ).ServeHTTP(refW, r) + + if w.Code != refW.Code { + t.Errorf( + "result http status code for grpc code %q and status %q should be equal to %d, but got %d", + tt.code, tt.status, refW.Code, w.Code, + ) + } + }) + } +} + +func TestWithHealthzEndpoint_serviceParam(t *testing.T) { + service := "test" + + // trigger error to output service in body + dummyClient := dummyHealthCheckClient{status: grpc_health_v1.HealthCheckResponse_UNKNOWN, code: codes.Unknown} + mux := runtime.NewServeMux(runtime.WithHealthzEndpoint(&dummyClient, 1 /* sid */)) + + r := httptest.NewRequest(http.MethodGet, "/healthz?service="+service, nil) + rr := httptest.NewRecorder() + + mux.ServeHTTP(rr, r) + + if !strings.Contains(rr.Body.String(), service) { + t.Errorf( + "service query parameter should be translated to HealthCheckRequest: expected %s to contain %s", + rr.Body.String(), service, + ) + } +} + +var _ grpc_health_v1.HealthClient = (*dummyHealthCheckClient)(nil) + +type dummyHealthCheckClient struct { + status grpc_health_v1.HealthCheckResponse_ServingStatus + code codes.Code +} + +func (g *dummyHealthCheckClient) Check(ctx context.Context, r *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (*grpc_health_v1.HealthCheckResponse, error) { + if g.code != codes.OK { + return nil, status.Error(g.code, r.GetService()) + } + + return &grpc_health_v1.HealthCheckResponse{Status: g.status}, nil +} + +func (g *dummyHealthCheckClient) Watch(ctx context.Context, r *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (grpc_health_v1.Health_WatchClient, error) { + return nil, status.Error(codes.Unimplemented, "unimplemented") +} diff --git a/gateway/runtime/pattern.go b/gateway/runtime/pattern.go index f319664..df7cb81 100644 --- a/gateway/runtime/pattern.go +++ b/gateway/runtime/pattern.go @@ -3,6 +3,7 @@ package runtime import ( "errors" "fmt" + "strconv" "strings" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" @@ -14,8 +15,16 @@ var ( ErrNotMatch = errors.New("not match to the path pattern") // ErrInvalidPattern indicates that the given definition of Pattern is not valid. ErrInvalidPattern = errors.New("invalid pattern") + // ErrMalformedSequence indicates that an escape sequence was malformed. + ErrMalformedSequence = errors.New("malformed escape sequence") ) +type MalformedSequenceError string + +func (e MalformedSequenceError) Error() string { + return "malformed path escape " + strconv.Quote(string(e)) +} + type op struct { code utilities.OpCode operand int @@ -140,10 +149,11 @@ func MustPattern(p Pattern, err error) Pattern { return p } -// Match examines components if it matches to the Pattern. -// If it matches, the function returns a mapping from field paths to their captured values. -// If otherwise, the function returns an error. -func (p Pattern) Match(components []string, verb string) (map[string]string, error) { +// MatchAndEscape examines components to determine if they match to a Pattern. +// MatchAndEscape will return an error if no Patterns matched or if a pattern +// matched but contained malformed escape sequences. If successful, the function +// returns a mapping from field paths to their captured values. +func (p Pattern) MatchAndEscape(components []string, verb string, unescapingMode UnescapingMode) (map[string]string, error) { if p.verb != verb { if p.verb != "" { return nil, ErrNotMatch @@ -154,7 +164,6 @@ func (p Pattern) Match(components []string, verb string) (map[string]string, err components = append([]string{}, components...) components[len(components)-1] += ":" + verb } - verb = "" } var pos int @@ -162,6 +171,8 @@ func (p Pattern) Match(components []string, verb string) (map[string]string, err captured := make([]string, len(p.vars)) l := len(components) for _, op := range p.ops { + var err error + switch op.code { case utilities.OpNop: continue @@ -174,6 +185,10 @@ func (p Pattern) Match(components []string, verb string) (map[string]string, err if lit := p.pool[op.operand]; c != lit { return nil, ErrNotMatch } + } else if op.code == utilities.OpPush { + if c, err = unescape(c, unescapingMode, false); err != nil { + return nil, err + } } stack = append(stack, c) pos++ @@ -183,7 +198,11 @@ func (p Pattern) Match(components []string, verb string) (map[string]string, err return nil, ErrNotMatch } end -= p.tailLen - stack = append(stack, strings.Join(components[pos:end], "/")) + c := strings.Join(components[pos:end], "/") + if c, err = unescape(c, unescapingMode, true); err != nil { + return nil, err + } + stack = append(stack, c) pos = end case utilities.OpConcatN: n := op.operand @@ -205,6 +224,16 @@ func (p Pattern) Match(components []string, verb string) (map[string]string, err return bindings, nil } +// MatchAndEscape examines components to determine if they match to a Pattern. +// It will never perform per-component unescaping (see: UnescapingModeLegacy). +// MatchAndEscape will return an error if no Patterns matched. If successful, +// the function returns a mapping from field paths to their captured values. +// +// Deprecated: Use MatchAndEscape. +func (p Pattern) Match(components []string, verb string) (map[string]string, error) { + return p.MatchAndEscape(components, verb, UnescapingModeDefault) +} + // Verb returns the verb part of the Pattern. func (p Pattern) Verb() string { return p.verb } @@ -235,3 +264,120 @@ func (p Pattern) String() string { } return "/" + segs } + +/* + * 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 +} + +// unescape unescapes a path string using the provided mode +func unescape(s string, mode UnescapingMode, multisegment bool) (string, error) { + // TODO(v3): remove UnescapingModeLegacy + if mode == UnescapingModeLegacy { + return s, nil + } + + if !multisegment { + mode = UnescapingModeAllCharacters + } + + // Count %, check that they're well-formed. + n := 0 + for i := 0; i < len(s); { + if s[i] == '%' { + 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 "", MalformedSequenceError(s) + } + i += 3 + } else { + i++ + } + } + + if n == 0 { + 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/gateway/runtime/pattern_test.go b/gateway/runtime/pattern_test.go deleted file mode 100644 index 1b856a5..0000000 --- a/gateway/runtime/pattern_test.go +++ /dev/null @@ -1,590 +0,0 @@ -package runtime - -import ( - "fmt" - "reflect" - "strings" - "testing" - - "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" -) - -const ( - validVersion = 1 - anything = 0 -) - -func TestNewPattern(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - verb string - - stackSizeWant, tailLenWant int - }{ - {}, - { - ops: []int{int(utilities.OpNop), anything}, - stackSizeWant: 0, - tailLenWant: 0, - }, - { - ops: []int{int(utilities.OpPush), anything}, - stackSizeWant: 1, - tailLenWant: 0, - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"abc"}, - stackSizeWant: 1, - tailLenWant: 0, - }, - { - ops: []int{int(utilities.OpPushM), anything}, - stackSizeWant: 1, - tailLenWant: 0, - }, - { - ops: []int{ - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - }, - stackSizeWant: 1, - tailLenWant: 0, - }, - { - ops: []int{ - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 0, - }, - pool: []string{"abc"}, - stackSizeWant: 1, - tailLenWant: 0, - }, - { - ops: []int{ - int(utilities.OpPush), anything, - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPushM), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - }, - pool: []string{"lit1", "lit2", "var1"}, - stackSizeWant: 4, - tailLenWant: 0, - }, - { - ops: []int{ - int(utilities.OpPushM), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 2, - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - }, - pool: []string{"lit1", "lit2", "var1"}, - stackSizeWant: 2, - tailLenWant: 2, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPushM), anything, - int(utilities.OpLitPush), 2, - int(utilities.OpConcatN), 3, - int(utilities.OpLitPush), 3, - int(utilities.OpCapture), 4, - }, - pool: []string{"lit1", "lit2", "lit3", "lit4", "var1"}, - stackSizeWant: 4, - tailLenWant: 2, - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"abc"}, - verb: "LOCK", - stackSizeWant: 1, - tailLenWant: 0, - }, - } { - pat, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb) - if err != nil { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, spec.verb, err) - continue - } - if got, want := pat.stacksize, spec.stackSizeWant; got != want { - t.Errorf("pat.stacksize = %d; want %d", got, want) - } - if got, want := pat.tailLen, spec.tailLenWant; got != want { - t.Errorf("pat.stacksize = %d; want %d", got, want) - } - } -} - -func TestNewPatternWithWrongOp(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - verb string - }{ - { - // op code out of bound - ops: []int{-1, anything}, - }, - { - // op code out of bound - ops: []int{int(utilities.OpEnd), 0}, - }, - { - // odd number of items - ops: []int{int(utilities.OpPush)}, - }, - { - // negative index - ops: []int{int(utilities.OpLitPush), -1}, - pool: []string{"abc"}, - }, - { - // index out of bound - ops: []int{int(utilities.OpLitPush), 1}, - pool: []string{"abc"}, - }, - { - // negative # of segments - ops: []int{int(utilities.OpConcatN), -1}, - pool: []string{"abc"}, - }, - { - // negative index - ops: []int{int(utilities.OpCapture), -1}, - pool: []string{"abc"}, - }, - { - // index out of bound - ops: []int{int(utilities.OpCapture), 1}, - pool: []string{"abc"}, - }, - { - // pushM appears twice - ops: []int{ - int(utilities.OpPushM), anything, - int(utilities.OpLitPush), 0, - int(utilities.OpPushM), anything, - }, - pool: []string{"abc"}, - }, - } { - _, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb) - if err == nil { - t.Errorf("NewPattern(%d, %v, %q, %q) succeeded; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, ErrInvalidPattern) - continue - } - if err != ErrInvalidPattern { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, err, ErrInvalidPattern) - continue - } - } -} - -func TestNewPatternWithStackUnderflow(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - verb string - }{ - { - ops: []int{int(utilities.OpConcatN), 1}, - }, - { - ops: []int{int(utilities.OpCapture), 0}, - pool: []string{"abc"}, - }, - } { - _, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb) - if err == nil { - t.Errorf("NewPattern(%d, %v, %q, %q) succeeded; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, ErrInvalidPattern) - continue - } - if err != ErrInvalidPattern { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, err, ErrInvalidPattern) - continue - } - } -} - -func TestMatch(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - verb string - - match []string - notMatch []string - }{ - { - match: []string{""}, - notMatch: []string{"example"}, - }, - { - ops: []int{int(utilities.OpNop), anything}, - match: []string{""}, - notMatch: []string{"example", "path/to/example"}, - }, - { - ops: []int{int(utilities.OpPush), anything}, - match: []string{"abc", "def"}, - notMatch: []string{"", "abc/def"}, - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"v1"}, - match: []string{"v1"}, - notMatch: []string{"", "v2"}, - }, - { - ops: []int{int(utilities.OpPushM), anything}, - match: []string{"", "abc", "abc/def", "abc/def/ghi"}, - }, - { - ops: []int{ - int(utilities.OpPushM), anything, - int(utilities.OpLitPush), 0, - }, - pool: []string{"tail"}, - match: []string{"tail", "abc/tail", "abc/def/tail"}, - notMatch: []string{ - "", "abc", "abc/def", - "tail/extra", "abc/tail/extra", "abc/def/tail/extra", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 2, - }, - pool: []string{"v1", "bucket", "name"}, - match: []string{"v1/bucket/my-bucket", "v1/bucket/our-bucket"}, - notMatch: []string{ - "", - "v1", - "v1/bucket", - "v2/bucket/my-bucket", - "v1/pubsub/my-topic", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPushM), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - }, - pool: []string{"v1", "o", "name"}, - match: []string{ - "v1/o", - "v1/o/my-bucket", - "v1/o/our-bucket", - "v1/o/my-bucket/dir", - "v1/o/my-bucket/dir/dir2", - "v1/o/my-bucket/dir/dir2/obj", - }, - notMatch: []string{ - "", - "v1", - "v2/o/my-bucket", - "v1/b/my-bucket", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - int(utilities.OpLitPush), 3, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 4, - }, - pool: []string{"v2", "b", "name", "o", "oname"}, - match: []string{ - "v2/b/my-bucket/o/obj", - "v2/b/our-bucket/o/obj", - "v2/b/my-bucket/o/dir", - }, - notMatch: []string{ - "", - "v2", - "v2/b", - "v2/b/my-bucket", - "v2/b/my-bucket/o", - }, - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"v1"}, - verb: "LOCK", - match: []string{"v1:LOCK"}, - notMatch: []string{"v1", "LOCK"}, - }, - } { - pat, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb) - if err != nil { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, spec.verb, err) - continue - } - - for _, path := range spec.match { - _, err = pat.Match(segments(path)) - if err != nil { - t.Errorf("pat.Match(%q) failed with %v; want success; pattern = (%v, %q)", path, err, spec.ops, spec.pool) - } - } - - for _, path := range spec.notMatch { - _, err = pat.Match(segments(path)) - if err == nil { - t.Errorf("pat.Match(%q) succeeded; want failure with %v; pattern = (%v, %q)", path, ErrNotMatch, spec.ops, spec.pool) - continue - } - if err != ErrNotMatch { - t.Errorf("pat.Match(%q) failed with %v; want failure with %v; pattern = (%v, %q)", spec.notMatch, err, ErrNotMatch, spec.ops, spec.pool) - } - } - } -} - -func TestMatchWithBinding(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - path string - verb string - - want map[string]string - }{ - { - want: make(map[string]string), - }, - { - ops: []int{int(utilities.OpNop), anything}, - want: make(map[string]string), - }, - { - ops: []int{int(utilities.OpPush), anything}, - path: "abc", - want: make(map[string]string), - }, - { - ops: []int{int(utilities.OpPush), anything}, - verb: "LOCK", - path: "abc:LOCK", - want: make(map[string]string), - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"endpoint"}, - path: "endpoint", - want: make(map[string]string), - }, - { - ops: []int{int(utilities.OpPushM), anything}, - path: "abc/def/ghi", - want: make(map[string]string), - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 2, - }, - pool: []string{"v1", "bucket", "name"}, - path: "v1/bucket/my-bucket", - want: map[string]string{ - "name": "my-bucket", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 2, - }, - pool: []string{"v1", "bucket", "name"}, - verb: "LOCK", - path: "v1/bucket/my-bucket:LOCK", - want: map[string]string{ - "name": "my-bucket", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPushM), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - }, - pool: []string{"v1", "o", "name"}, - path: "v1/o/my-bucket/dir/dir2/obj", - want: map[string]string{ - "name": "o/my-bucket/dir/dir2/obj", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPushM), anything, - int(utilities.OpLitPush), 2, - int(utilities.OpConcatN), 3, - int(utilities.OpCapture), 4, - int(utilities.OpLitPush), 3, - }, - pool: []string{"v1", "o", ".ext", "tail", "name"}, - path: "v1/o/my-bucket/dir/dir2/obj/.ext/tail", - want: map[string]string{ - "name": "o/my-bucket/dir/dir2/obj/.ext", - }, - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - int(utilities.OpLitPush), 3, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 4, - }, - pool: []string{"v2", "b", "name", "o", "oname"}, - path: "v2/b/my-bucket/o/obj", - want: map[string]string{ - "name": "b/my-bucket", - "oname": "obj", - }, - }, - } { - pat, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb) - if err != nil { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, spec.verb, err) - continue - } - - got, err := pat.Match(segments(spec.path)) - if err != nil { - t.Errorf("pat.Match(%q) failed with %v; want success; pattern = (%v, %q)", spec.path, err, spec.ops, spec.pool) - } - if !reflect.DeepEqual(got, spec.want) { - t.Errorf("pat.Match(%q) = %q; want %q; pattern = (%v, %q)", spec.path, got, spec.want, spec.ops, spec.pool) - } - } -} - -func segments(path string) (components []string, verb string) { - if path == "" { - return nil, "" - } - components = strings.Split(path, "/") - l := len(components) - c := components[l-1] - if idx := strings.LastIndex(c, ":"); idx >= 0 { - components[l-1], verb = c[:idx], c[idx+1:] - } - return components, verb -} - -func TestPatternString(t *testing.T) { - for _, spec := range []struct { - ops []int - pool []string - - want string - }{ - { - want: "/", - }, - { - ops: []int{int(utilities.OpNop), anything}, - want: "/", - }, - { - ops: []int{int(utilities.OpPush), anything}, - want: "/*", - }, - { - ops: []int{int(utilities.OpLitPush), 0}, - pool: []string{"endpoint"}, - want: "/endpoint", - }, - { - ops: []int{int(utilities.OpPushM), anything}, - want: "/**", - }, - { - ops: []int{ - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - }, - want: "/*", - }, - { - ops: []int{ - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 1, - int(utilities.OpCapture), 0, - }, - pool: []string{"name"}, - want: "/{name=*}", - }, - { - ops: []int{ - int(utilities.OpLitPush), 0, - int(utilities.OpLitPush), 1, - int(utilities.OpPush), anything, - int(utilities.OpConcatN), 2, - int(utilities.OpCapture), 2, - int(utilities.OpLitPush), 3, - int(utilities.OpPushM), anything, - int(utilities.OpLitPush), 4, - int(utilities.OpConcatN), 3, - int(utilities.OpCapture), 6, - int(utilities.OpLitPush), 5, - }, - pool: []string{"v1", "buckets", "bucket_name", "objects", ".ext", "tail", "name"}, - want: "/v1/{bucket_name=buckets/*}/{name=objects/**/.ext}/tail", - }, - } { - p, err := NewPattern(validVersion, spec.ops, spec.pool, "") - if err != nil { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, "", err) - continue - } - if got, want := p.String(), spec.want; got != want { - t.Errorf("%#v.String() = %q; want %q", p, got, want) - } - - verb := "LOCK" - p, err = NewPattern(validVersion, spec.ops, spec.pool, verb) - if err != nil { - t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, verb, err) - continue - } - if got, want := p.String(), fmt.Sprintf("%s:%s", spec.want, verb); got != want { - t.Errorf("%#v.String() = %q; want %q", p, got, want) - } - } -} diff --git a/gateway/runtime/proto2_convert.go b/gateway/runtime/proto2_convert.go deleted file mode 100644 index d549407..0000000 --- a/gateway/runtime/proto2_convert.go +++ /dev/null @@ -1,80 +0,0 @@ -package runtime - -import ( - "google.golang.org/protobuf/proto" -) - -// StringP returns a pointer to a string whose pointee is same as the given string value. -func StringP(val string) (*string, error) { - return proto.String(val), nil -} - -// BoolP parses the given string representation of a boolean value, -// and returns a pointer to a bool whose value is same as the parsed value. -func BoolP(val string) (*bool, error) { - b, err := Bool(val) - if err != nil { - return nil, err - } - return proto.Bool(b), nil -} - -// Float64P parses the given string representation of a floating point number, -// and returns a pointer to a float64 whose value is same as the parsed number. -func Float64P(val string) (*float64, error) { - f, err := Float64(val) - if err != nil { - return nil, err - } - return proto.Float64(f), nil -} - -// Float32P parses the given string representation of a floating point number, -// and returns a pointer to a float32 whose value is same as the parsed number. -func Float32P(val string) (*float32, error) { - f, err := Float32(val) - if err != nil { - return nil, err - } - return proto.Float32(f), nil -} - -// Int64P parses the given string representation of an integer -// and returns a pointer to a int64 whose value is same as the parsed integer. -func Int64P(val string) (*int64, error) { - i, err := Int64(val) - if err != nil { - return nil, err - } - return proto.Int64(i), nil -} - -// Int32P parses the given string representation of an integer -// and returns a pointer to a int32 whose value is same as the parsed integer. -func Int32P(val string) (*int32, error) { - i, err := Int32(val) - if err != nil { - return nil, err - } - return proto.Int32(i), err -} - -// Uint64P parses the given string representation of an integer -// and returns a pointer to a uint64 whose value is same as the parsed integer. -func Uint64P(val string) (*uint64, error) { - i, err := Uint64(val) - if err != nil { - return nil, err - } - return proto.Uint64(i), err -} - -// Uint32P parses the given string representation of an integer -// and returns a pointer to a uint32 whose value is same as the parsed integer. -func Uint32P(val string) (*uint32, error) { - i, err := Uint32(val) - if err != nil { - return nil, err - } - return proto.Uint32(i), err -} diff --git a/gateway/runtime/query.go b/gateway/runtime/query.go index 9a9f3d3..fb0c84e 100644 --- a/gateway/runtime/query.go +++ b/gateway/runtime/query.go @@ -10,14 +10,15 @@ import ( "strings" "time" - "github.com/golang/protobuf/ptypes" - wrapperspb "github.com/golang/protobuf/ptypes/wrappers" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/genproto/protobuf/field_mask" "google.golang.org/grpc/grpclog" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" ) var valuesKeyRegexp = regexp.MustCompile(`^(.*)\[(.*)\]$`) @@ -233,7 +234,7 @@ func parseField(fieldDescriptor protoreflect.FieldDescriptor, value string) (pro case protoreflect.StringKind: return protoreflect.ValueOfString(value), nil case protoreflect.BytesKind: - v, err := base64.StdEncoding.DecodeString(value) + v, err := base64.URLEncoding.DecodeString(value) if err != nil { return protoreflect.Value{}, err } @@ -256,10 +257,7 @@ func parseMessage(msgDescriptor protoreflect.MessageDescriptor, value string) (p if err != nil { return protoreflect.Value{}, err } - msg, err = ptypes.TimestampProto(t) - if err != nil { - return protoreflect.Value{}, err - } + msg = timestamppb.New(t) case "google.protobuf.Duration": if value == "null" { break @@ -268,7 +266,7 @@ func parseMessage(msgDescriptor protoreflect.MessageDescriptor, value string) (p if err != nil { return protoreflect.Value{}, err } - msg = ptypes.DurationProto(d) + msg = durationpb.New(d) case "google.protobuf.DoubleValue": v, err := strconv.ParseFloat(value, 64) if err != nil { @@ -314,7 +312,7 @@ func parseMessage(msgDescriptor protoreflect.MessageDescriptor, value string) (p case "google.protobuf.StringValue": msg = &wrapperspb.StringValue{Value: value} case "google.protobuf.BytesValue": - v, err := base64.StdEncoding.DecodeString(value) + v, err := base64.URLEncoding.DecodeString(value) if err != nil { return protoreflect.Value{}, err } diff --git a/gateway/runtime/query_test.go b/gateway/runtime/query_test.go deleted file mode 100644 index ee6667a..0000000 --- a/gateway/runtime/query_test.go +++ /dev/null @@ -1,610 +0,0 @@ -package runtime_test - -import ( - "errors" - "net/url" - "strconv" - "testing" - "time" - - "github.com/golang/protobuf/ptypes" - wrapperspb "github.com/golang/protobuf/ptypes/wrappers" - "github.com/google/go-cmp/cmp" - // "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/binchencoder/ease-gateway/gateway/runtime" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" - "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" - "google.golang.org/genproto/protobuf/field_mask" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/testing/protocmp" -) - -func BenchmarkPopulateQueryParameters(b *testing.B) { - timeT := time.Date(2016, time.December, 15, 12, 23, 32, 49, time.UTC) - timeStr := timeT.Format(time.RFC3339Nano) - - durationT := 13 * time.Hour - durationStr := durationT.String() - - fieldmaskStr := "float_value,double_value" - - msg := &examplepb.Proto3Message{} - values := url.Values{ - "float_value": {"1.5"}, - "double_value": {"2.5"}, - "int64_value": {"-1"}, - "int32_value": {"-2"}, - "uint64_value": {"3"}, - "uint32_value": {"4"}, - "bool_value": {"true"}, - "string_value": {"str"}, - "bytes_value": {"Ynl0ZXM="}, - "repeated_value": {"a", "b", "c"}, - "enum_value": {"1"}, - "repeated_enum": {"1", "2", "0"}, - "timestamp_value": {timeStr}, - "duration_value": {durationStr}, - "fieldmask_value": {fieldmaskStr}, - "wrapper_float_value": {"1.5"}, - "wrapper_double_value": {"2.5"}, - "wrapper_int64_value": {"-1"}, - "wrapper_int32_value": {"-2"}, - "wrapper_u_int64_value": {"3"}, - "wrapper_u_int32_value": {"4"}, - "wrapper_bool_value": {"true"}, - "wrapper_string_value": {"str"}, - "wrapper_bytes_value": {"Ynl0ZXM="}, - "map_value[key]": {"value"}, - "map_value[second]": {"bar"}, - "map_value[third]": {"zzz"}, - "map_value[fourth]": {""}, - `map_value[~!@#$%^&*()]`: {"value"}, - "map_value2[key]": {"-2"}, - "map_value3[-2]": {"value"}, - "map_value4[key]": {"-1"}, - "map_value5[-1]": {"value"}, - "map_value6[key]": {"3"}, - "map_value7[3]": {"value"}, - "map_value8[key]": {"4"}, - "map_value9[4]": {"value"}, - "map_value10[key]": {"1.5"}, - "map_value11[1.5]": {"value"}, - "map_value12[key]": {"2.5"}, - "map_value13[2.5]": {"value"}, - "map_value14[key]": {"true"}, - "map_value15[true]": {"value"}, - } - filter := utilities.NewDoubleArray([][]string{ - {"bool_value"}, {"repeated_value"}, - }) - - for i := 0; i < b.N; i++ { - _ = runtime.PopulateQueryParameters(msg, values, filter) - } -} - -func TestPopulateParameters(t *testing.T) { - timeT := time.Date(2016, time.December, 15, 12, 23, 32, 49, time.UTC) - timeStr := timeT.Format(time.RFC3339Nano) - timePb, err := ptypes.TimestampProto(timeT) - if err != nil { - t.Fatalf("Couldn't setup timestamp in Protobuf format: %v", err) - } - - durationT := 13 * time.Hour - durationStr := durationT.String() - durationPb := ptypes.DurationProto(durationT) - - fieldmaskStr := "float_value,double_value" - fieldmaskPb := &field_mask.FieldMask{Paths: []string{"float_value", "double_value"}} - - for i, spec := range []struct { - values url.Values - filter *utilities.DoubleArray - want proto.Message - wanterr error - }{ - { - values: url.Values{ - "float_value": {"1.5"}, - "double_value": {"2.5"}, - "int64_value": {"-1"}, - "int32_value": {"-2"}, - "uint64_value": {"3"}, - "uint32_value": {"4"}, - "bool_value": {"true"}, - "string_value": {"str"}, - "bytes_value": {"Ynl0ZXM="}, - "repeated_value": {"a", "b", "c"}, - "repeated_message": {"1", "2", "3"}, - "enum_value": {"1"}, - "repeated_enum": {"1", "2", "0"}, - "timestamp_value": {timeStr}, - "duration_value": {durationStr}, - "fieldmask_value": {fieldmaskStr}, - "wrapper_float_value": {"1.5"}, - "wrapper_double_value": {"2.5"}, - "wrapper_int64_value": {"-1"}, - "wrapper_int32_value": {"-2"}, - "wrapper_u_int64_value": {"3"}, - "wrapper_u_int32_value": {"4"}, - "wrapper_bool_value": {"true"}, - "wrapper_string_value": {"str"}, - "wrapper_bytes_value": {"Ynl0ZXM="}, - "map_value[key]": {"value"}, - "map_value[second]": {"bar"}, - "map_value[third]": {"zzz"}, - "map_value[fourth]": {""}, - `map_value[~!@#$%^&*()]`: {"value"}, - "map_value2[key]": {"-2"}, - "map_value3[-2]": {"value"}, - "map_value4[key]": {"-1"}, - "map_value5[-1]": {"value"}, - "map_value6[key]": {"3"}, - "map_value7[3]": {"value"}, - "map_value8[key]": {"4"}, - "map_value9[4]": {"value"}, - "map_value10[key]": {"1.5"}, - "map_value11[1.5]": {"value"}, - "map_value12[key]": {"2.5"}, - "map_value13[2.5]": {"value"}, - "map_value14[key]": {"true"}, - "map_value15[true]": {"value"}, - "map_value16[key]": {"2"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - FloatValue: 1.5, - DoubleValue: 2.5, - Int64Value: -1, - Int32Value: -2, - Uint64Value: 3, - Uint32Value: 4, - BoolValue: true, - StringValue: "str", - BytesValue: []byte("bytes"), - RepeatedValue: []string{"a", "b", "c"}, - RepeatedMessage: []*wrapperspb.UInt64Value{{Value: 1}, {Value: 2}, {Value: 3}}, - EnumValue: examplepb.EnumValue_Y, - RepeatedEnum: []examplepb.EnumValue{examplepb.EnumValue_Y, examplepb.EnumValue_Z, examplepb.EnumValue_X}, - TimestampValue: timePb, - DurationValue: durationPb, - FieldmaskValue: fieldmaskPb, - WrapperFloatValue: &wrapperspb.FloatValue{Value: 1.5}, - WrapperDoubleValue: &wrapperspb.DoubleValue{Value: 2.5}, - WrapperInt64Value: &wrapperspb.Int64Value{Value: -1}, - WrapperInt32Value: &wrapperspb.Int32Value{Value: -2}, - WrapperUInt64Value: &wrapperspb.UInt64Value{Value: 3}, - WrapperUInt32Value: &wrapperspb.UInt32Value{Value: 4}, - WrapperBoolValue: &wrapperspb.BoolValue{Value: true}, - WrapperStringValue: &wrapperspb.StringValue{Value: "str"}, - WrapperBytesValue: &wrapperspb.BytesValue{Value: []byte("bytes")}, - MapValue: map[string]string{ - "key": "value", - "second": "bar", - "third": "zzz", - "fourth": "", - `~!@#$%^&*()`: "value", - }, - MapValue2: map[string]int32{"key": -2}, - MapValue3: map[int32]string{-2: "value"}, - MapValue4: map[string]int64{"key": -1}, - MapValue5: map[int64]string{-1: "value"}, - MapValue6: map[string]uint32{"key": 3}, - MapValue7: map[uint32]string{3: "value"}, - MapValue8: map[string]uint64{"key": 4}, - MapValue9: map[uint64]string{4: "value"}, - MapValue10: map[string]float32{"key": 1.5}, - MapValue12: map[string]float64{"key": 2.5}, - MapValue14: map[string]bool{"key": true}, - MapValue15: map[bool]string{true: "value"}, - MapValue16: map[string]*wrapperspb.UInt64Value{"key": {Value: 2}}, - }, - }, - { - values: url.Values{ - "floatValue": {"1.5"}, - "doubleValue": {"2.5"}, - "int64Value": {"-1"}, - "int32Value": {"-2"}, - "uint64Value": {"3"}, - "uint32Value": {"4"}, - "boolValue": {"true"}, - "stringValue": {"str"}, - "bytesValue": {"Ynl0ZXM="}, - "repeatedValue": {"a", "b", "c"}, - "enumValue": {"1"}, - "repeatedEnum": {"1", "2", "0"}, - "timestampValue": {timeStr}, - "durationValue": {durationStr}, - "fieldmaskValue": {fieldmaskStr}, - "wrapperFloatValue": {"1.5"}, - "wrapperDoubleValue": {"2.5"}, - "wrapperInt64Value": {"-1"}, - "wrapperInt32Value": {"-2"}, - "wrapperUInt64Value": {"3"}, - "wrapperUInt32Value": {"4"}, - "wrapperBoolValue": {"true"}, - "wrapperStringValue": {"str"}, - "wrapperBytesValue": {"Ynl0ZXM="}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - FloatValue: 1.5, - DoubleValue: 2.5, - Int64Value: -1, - Int32Value: -2, - Uint64Value: 3, - Uint32Value: 4, - BoolValue: true, - StringValue: "str", - BytesValue: []byte("bytes"), - RepeatedValue: []string{"a", "b", "c"}, - EnumValue: examplepb.EnumValue_Y, - RepeatedEnum: []examplepb.EnumValue{examplepb.EnumValue_Y, examplepb.EnumValue_Z, examplepb.EnumValue_X}, - TimestampValue: timePb, - DurationValue: durationPb, - FieldmaskValue: fieldmaskPb, - WrapperFloatValue: &wrapperspb.FloatValue{Value: 1.5}, - WrapperDoubleValue: &wrapperspb.DoubleValue{Value: 2.5}, - WrapperInt64Value: &wrapperspb.Int64Value{Value: -1}, - WrapperInt32Value: &wrapperspb.Int32Value{Value: -2}, - WrapperUInt64Value: &wrapperspb.UInt64Value{Value: 3}, - WrapperUInt32Value: &wrapperspb.UInt32Value{Value: 4}, - WrapperBoolValue: &wrapperspb.BoolValue{Value: true}, - WrapperStringValue: &wrapperspb.StringValue{Value: "str"}, - WrapperBytesValue: &wrapperspb.BytesValue{Value: []byte("bytes")}, - }, - }, - { - values: url.Values{ - "enum_value": {"Z"}, - "repeated_enum": {"X", "2", "0"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - EnumValue: examplepb.EnumValue_Z, - RepeatedEnum: []examplepb.EnumValue{examplepb.EnumValue_X, examplepb.EnumValue_Z, examplepb.EnumValue_X}, - }, - }, - { - values: url.Values{ - "float_value": {"1.5"}, - "double_value": {"2.5"}, - "int64_value": {"-1"}, - "int32_value": {"-2"}, - "uint64_value": {"3"}, - "uint32_value": {"4"}, - "bool_value": {"true"}, - "string_value": {"str"}, - "repeated_value": {"a", "b", "c"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto2Message{ - FloatValue: proto.Float32(1.5), - DoubleValue: proto.Float64(2.5), - Int64Value: proto.Int64(-1), - Int32Value: proto.Int32(-2), - Uint64Value: proto.Uint64(3), - Uint32Value: proto.Uint32(4), - BoolValue: proto.Bool(true), - StringValue: proto.String("str"), - RepeatedValue: []string{"a", "b", "c"}, - }, - }, - { - values: url.Values{ - "floatValue": {"1.5"}, - "doubleValue": {"2.5"}, - "int64Value": {"-1"}, - "int32Value": {"-2"}, - "uint64Value": {"3"}, - "uint32Value": {"4"}, - "boolValue": {"true"}, - "stringValue": {"str"}, - "repeatedValue": {"a", "b", "c"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto2Message{ - FloatValue: proto.Float32(1.5), - DoubleValue: proto.Float64(2.5), - Int64Value: proto.Int64(-1), - Int32Value: proto.Int32(-2), - Uint64Value: proto.Uint64(3), - Uint32Value: proto.Uint32(4), - BoolValue: proto.Bool(true), - StringValue: proto.String("str"), - RepeatedValue: []string{"a", "b", "c"}, - }, - }, - { - values: url.Values{ - "nested.nested.nested.repeated_value": {"a", "b", "c"}, - "nested.nested.nested.string_value": {"s"}, - "nested.nested.string_value": {"t"}, - "nested.string_value": {"u"}, - "nested.nested.map_value[first]": {"foo"}, - "nested.nested.map_value[second]": {"bar"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - Nested: &examplepb.Proto3Message{ - Nested: &examplepb.Proto3Message{ - MapValue: map[string]string{ - "first": "foo", - "second": "bar", - }, - Nested: &examplepb.Proto3Message{ - RepeatedValue: []string{"a", "b", "c"}, - StringValue: "s", - }, - StringValue: "t", - }, - StringValue: "u", - }, - }, - }, - { - values: url.Values{ - "oneof_string_value": {"foobar"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - OneofValue: &examplepb.Proto3Message_OneofStringValue{ - OneofStringValue: "foobar", - }, - }, - }, - { - values: url.Values{ - "oneofStringValue": {"foobar"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - OneofValue: &examplepb.Proto3Message_OneofStringValue{ - OneofStringValue: "foobar", - }, - }, - }, - { - values: url.Values{ - "oneof_bool_value": {"true"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{ - OneofValue: &examplepb.Proto3Message_OneofBoolValue{ - OneofBoolValue: true, - }, - }, - }, - { - // Don't allow setting a oneof more than once - values: url.Values{ - "oneof_bool_value": {"true"}, - "oneof_string_value": {"foobar"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{}, - wanterr: errors.New("field already set for oneof \"oneof_value\""), - }, - { - // Error when there are too many values - values: url.Values{ - "uint64_value": {"1", "2"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{}, - wanterr: errors.New("too many values for field \"uint64_value\": 1, 2"), - }, - { - // Error when dereferencing a list of messages - values: url.Values{ - "repeated_message.value": {"1"}, - }, - filter: utilities.NewDoubleArray(nil), - want: &examplepb.Proto3Message{}, - wanterr: errors.New("invalid path: \"repeated_message\" is not a message"), - }, - } { - t.Run(strconv.Itoa(i), func(t *testing.T) { - msg := spec.want.ProtoReflect().New().Interface() - err := runtime.PopulateQueryParameters(msg, spec.values, spec.filter) - if spec.wanterr != nil { - if err == nil || err.Error() != spec.wanterr.Error() { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) failed with %q; want error %q", spec.values, spec.filter, err, spec.wanterr) - } - return - } - - if err != nil { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) failed with %v; want success", spec.values, spec.filter, err) - return - } - if diff := cmp.Diff(spec.want, msg, protocmp.Transform()); diff != "" { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v): %s", spec.values, spec.filter, diff) - } - }) - } -} - -func TestPopulateParametersWithFilters(t *testing.T) { - for _, spec := range []struct { - values url.Values - filter *utilities.DoubleArray - want proto.Message - }{ - { - values: url.Values{ - "bool_value": {"true"}, - "string_value": {"str"}, - "repeated_value": {"a", "b", "c"}, - }, - filter: utilities.NewDoubleArray([][]string{ - {"bool_value"}, {"repeated_value"}, - }), - want: &examplepb.Proto3Message{ - StringValue: "str", - }, - }, - { - values: url.Values{ - "nested.nested.bool_value": {"true"}, - "nested.nested.string_value": {"str"}, - "nested.string_value": {"str"}, - "string_value": {"str"}, - }, - filter: utilities.NewDoubleArray([][]string{ - {"nested"}, - }), - want: &examplepb.Proto3Message{ - StringValue: "str", - }, - }, - { - values: url.Values{ - "nested.nested.bool_value": {"true"}, - "nested.nested.string_value": {"str"}, - "nested.string_value": {"str"}, - "string_value": {"str"}, - }, - filter: utilities.NewDoubleArray([][]string{ - {"nested", "nested"}, - }), - want: &examplepb.Proto3Message{ - Nested: &examplepb.Proto3Message{ - StringValue: "str", - }, - StringValue: "str", - }, - }, - { - values: url.Values{ - "nested.nested.bool_value": {"true"}, - "nested.nested.string_value": {"str"}, - "nested.string_value": {"str"}, - "string_value": {"str"}, - }, - filter: utilities.NewDoubleArray([][]string{ - {"nested", "nested", "string_value"}, - }), - want: &examplepb.Proto3Message{ - Nested: &examplepb.Proto3Message{ - StringValue: "str", - Nested: &examplepb.Proto3Message{ - BoolValue: true, - }, - }, - StringValue: "str", - }, - }, - } { - msg := spec.want.ProtoReflect().New().Interface() - err := runtime.PopulateQueryParameters(msg, spec.values, spec.filter) - if err != nil { - t.Errorf("runtime.PoplateQueryParameters(msg, %v, %v) failed with %v; want success", spec.values, spec.filter, err) - continue - } - if got, want := msg, spec.want; !proto.Equal(got, want) { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v = %v; want %v", spec.values, spec.filter, got, want) - } - } -} - -func TestPopulateQueryParametersWithInvalidNestedParameters(t *testing.T) { - for _, spec := range []struct { - msg proto.Message - values url.Values - filter *utilities.DoubleArray - }{ - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "float_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "double_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "int64_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "int32_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "uint64_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "uint32_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "bool_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "string_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "repeated_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "enum_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "enum_value.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - { - msg: &examplepb.Proto3Message{}, - values: url.Values{ - "repeated_enum.nested": {"test"}, - }, - filter: utilities.NewDoubleArray(nil), - }, - } { - spec.msg = spec.msg.ProtoReflect().New().Interface() - err := runtime.PopulateQueryParameters(spec.msg, spec.values, spec.filter) - if err == nil { - t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) did not fail; want error", spec.values, spec.filter) - } - } -} diff --git a/go.mod b/go.mod index 5c9000c..5b4d68e 100644 --- a/go.mod +++ b/go.mod @@ -1,29 +1,37 @@ module github.com/binchencoder/ease-gateway -go 1.13 +go 1.17 require ( github.com/binchencoder/gateway-proto v0.0.7 github.com/binchencoder/letsgo v0.0.3 github.com/binchencoder/skylb-api v0.0.5 - github.com/fatih/color v1.9.0 - github.com/ghodss/yaml v1.0.0 - github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b - github.com/golang/protobuf v1.4.3 - github.com/google/go-cmp v0.5.2 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 - github.com/klauspost/compress v1.10.10 - github.com/pborman/uuid v1.2.0 - github.com/prometheus/client_golang v1.7.1 - golang.org/x/net v0.0.0-20200822124328-c89045814202 - google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 - google.golang.org/grpc v1.33.1 - google.golang.org/protobuf v1.25.0 + github.com/antihax/optional v1.0.0 + github.com/golang/glog v1.0.0 + github.com/golang/protobuf v1.5.2 + github.com/google/go-cmp v0.5.7 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.8.0 + github.com/rogpeppe/fastuuid v1.2.0 + golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a + google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 + google.golang.org/grpc v1.45.0 + google.golang.org/protobuf v1.27.1 + gopkg.in/yaml.v2 v2.4.0 + sigs.k8s.io/yaml v1.3.0 +) + +require ( + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/appengine v1.6.6 // indirect ) replace ( github.com/coreos/bbolt v1.3.4 => go.etcd.io/bbolt v1.3.4 github.com/coreos/bbolt v1.3.5 => go.etcd.io/bbolt v1.3.5 - google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.29.1 - google.golang.org/grpc v1.33.1 => google.golang.org/grpc v1.29.1 + // google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.29.1 + // google.golang.org/grpc v1.33.1 => google.golang.org/grpc v1.29.1 + // google.golang.org/grpc => google.golang.org/grpc v1.29.1 ) diff --git a/go.sum b/go.sum index 2960acb..97044f8 100644 --- a/go.sum +++ b/go.sum @@ -133,6 +133,7 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -160,6 +161,9 @@ github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= 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 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -173,6 +177,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -208,6 +214,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4G github.com/grpc-ecosystem/grpc-gateway v1.15.2 h1:HC+hWRWf+v5zTMPyoaYTKIJih+4sd4XRWmj0qlG87Co= github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 h1:X2vfSnm1WC8HEo0MBHZg2TcuDUHJj6kd1TmEAQncnSA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1/go.mod h1:oVMjMN64nzEcepv1kdZKgx1qNYt4Ro0Gqefiq2JWdis= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.8.0/go.mod h1:/fckq3NE+vGiJsd4fDt4ge1XrK8cN+e5G5QWIzdg7Q8= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -492,12 +499,15 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201026091529-146b70c837a4 h1:awiuzyrRjJDb+OXi9ceHO3SDxVoN3JER57mhtqkdQBs= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 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= @@ -547,6 +557,13 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -554,6 +571,8 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -673,6 +692,7 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 h1:bFFRpT+e8JJVY7lMMfvezL1ZIwqiwmPl2bsE2yx4HqM= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -710,6 +730,10 @@ google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEG google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -729,6 +753,7 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -744,6 +769,7 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= upper.io/db.v3 v3.7.1+incompatible h1:GiK/NmDUClH3LrZd54qj5OQsz8brGFv652QXyRXtg2U= upper.io/db.v3 v3.7.1+incompatible/go.mod h1:FgTdD24eBjJAbPKsQSiHUNgXjOR4Lub3u1UMHSIh82Y= diff --git a/httpoptions/BUILD.bazel b/httpoptions/BUILD.bazel index 0bd1eba..11e15fe 100644 --- a/httpoptions/BUILD.bazel +++ b/httpoptions/BUILD.bazel @@ -12,7 +12,7 @@ filegroup( ) go_library( - name = "go_default_library", + name = "httpoptions", embed = [":options_go_proto"], importpath = "github.com/binchencoder/ease-gateway/httpoptions", ) @@ -35,22 +35,28 @@ go_proto_library( name = "options_go_proto", compilers = ["@io_bazel_rules_go//proto:go_grpc"], importpath = "github.com/binchencoder/ease-gateway/httpoptions", - proto = ":ease_api_proto", + proto = ":options_proto", deps = [ "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", ], ) -proto_library( - name = "ease_api_proto", - srcs = [ - "annotations.proto", - "http.proto", - ], - deps = [ - "@com_github_binchencoder_gateway_proto//data:data_proto", - "@com_github_binchencoder_gateway_proto//frontend:error_proto", - "@com_google_protobuf//:descriptor_proto", - ], +# proto_library( +# name = "ease_api_proto", +# srcs = [ +# "annotations.proto", +# "http.proto", +# ], +# deps = [ +# "@com_github_binchencoder_gateway_proto//data:data_proto", +# "@com_github_binchencoder_gateway_proto//frontend:error_proto", +# "@com_google_protobuf//:descriptor_proto", +# ], +# ) + +alias( + name = "go_default_library", + actual = ":options_go_proto", + visibility = ["//visibility:public"], ) diff --git a/httpoptions/annotations.pb.go b/httpoptions/annotations.pb.go old mode 100644 new mode 100755 index 75acf02..599940e --- a/httpoptions/annotations.pb.go +++ b/httpoptions/annotations.pb.go @@ -1,34 +1,17 @@ -// Copyright (c) 2015, Google Inc. -// -// 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. - -// See `https://github.com/googleapis/googleapis/blob/master/google/api/annotations.proto` - // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: httpoptions/annotations.proto -package ease_api +package annotations import ( - data "data" - _ "frontend" - proto "github.com/golang/protobuf/proto" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" + data "github.com/binchencoder/gateway-proto/data" + _ "github.com/binchencoder/gateway-proto/frontend" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" reflect "reflect" sync "sync" ) @@ -40,16 +23,11 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -// Api regist gateway. type ApiSourceType int32 const ( - ApiSourceType_EASE_GATEWAY ApiSourceType = 0 // ease-gateway apis. - ApiSourceType_OPEN_GATEWAY ApiSourceType = 1 // open-gateway open apis. + ApiSourceType_EASE_GATEWAY ApiSourceType = 0 + ApiSourceType_OPEN_GATEWAY ApiSourceType = 1 ) // Enum value maps for ApiSourceType. @@ -91,12 +69,11 @@ func (ApiSourceType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{0} } -// Auth token type. type AuthTokenType int32 const ( - AuthTokenType_EASE_AUTH_TOKEN AuthTokenType = 0 // ease gateway auth type. - AuthTokenType_BASE_ACCESS_TOKEN AuthTokenType = 1 // open platform baseAccessToken. + AuthTokenType_EASE_AUTH_TOKEN AuthTokenType = 0 + AuthTokenType_BASE_ACCESS_TOKEN AuthTokenType = 1 ) // Enum value maps for AuthTokenType. @@ -138,12 +115,11 @@ func (AuthTokenType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{1} } -// Specified source Type. type SpecSourceType int32 const ( - SpecSourceType_UNSPECIFIED SpecSourceType = 0 // use the value of x-source about header. - SpecSourceType_WEB SpecSourceType = 1 // specify x-source as "web". + SpecSourceType_UNSPECIFIED SpecSourceType = 0 + SpecSourceType_WEB SpecSourceType = 1 ) // Enum value maps for SpecSourceType. @@ -185,12 +161,11 @@ func (SpecSourceType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{2} } -// The load balancer enums. type LoadBalancer int32 const ( LoadBalancer_ROUND_ROBIN LoadBalancer = 0 - LoadBalancer_CONSISTENT LoadBalancer = 1 // Consistent hashing. + LoadBalancer_CONSISTENT LoadBalancer = 1 ) // Enum value maps for LoadBalancer. @@ -232,19 +207,18 @@ func (LoadBalancer) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{3} } -// The opertaion type. type OperatorType int32 const ( OperatorType_OPERATOR_TYPE_UNKNOWN OperatorType = 0 - OperatorType_GT OperatorType = 1 // Greater than - OperatorType_LT OperatorType = 2 // Less than - OperatorType_EQ OperatorType = 3 // Equals - OperatorType_MATCH OperatorType = 4 // String pattern match. - OperatorType_NON_NIL OperatorType = 5 // Not nil - OperatorType_LEN_GT OperatorType = 6 // String length great than - OperatorType_LEN_LT OperatorType = 7 // String length less than - OperatorType_LEN_EQ OperatorType = 8 // String length equals + OperatorType_GT OperatorType = 1 + OperatorType_LT OperatorType = 2 + OperatorType_EQ OperatorType = 3 + OperatorType_MATCH OperatorType = 4 + OperatorType_NON_NIL OperatorType = 5 + OperatorType_LEN_GT OperatorType = 6 + OperatorType_LEN_LT OperatorType = 7 + OperatorType_LEN_EQ OperatorType = 8 ) // Enum value maps for OperatorType. @@ -300,12 +274,11 @@ func (OperatorType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{4} } -// The supported function type list type FunctionType int32 const ( FunctionType_FUNCTION_TYPE_UNKNOWN FunctionType = 0 - FunctionType_TRIM FunctionType = 1 // String trim. + FunctionType_TRIM FunctionType = 1 ) // Enum value maps for FunctionType. @@ -347,13 +320,12 @@ func (FunctionType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{5} } -// ValueType is the type of the field. type ValueType int32 const ( ValueType_VALUE_TYPE_UNKNOWN ValueType = 0 - ValueType_NUMBER ValueType = 1 // Represent all number type like int,real - ValueType_STRING ValueType = 2 // String + ValueType_NUMBER ValueType = 1 + ValueType_STRING ValueType = 2 ValueType_OBJ ValueType = 3 ) @@ -400,33 +372,19 @@ func (ValueType) EnumDescriptor() ([]byte, []int) { return file_httpoptions_annotations_proto_rawDescGZIP(), []int{6} } -// The api method. type ApiMethod struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - LoginNotRequired bool `protobuf:"varint,1,opt,name=login_not_required,json=loginNotRequired,proto3" json:"login_not_required,omitempty"` - ClientSignRequired bool `protobuf:"varint,2,opt,name=client_sign_required,json=clientSignRequired,proto3" json:"client_sign_required,omitempty"` - // Used only for CONSISTENT load balancer. - // Can take the following formats: - // - "field.field.field": hash key from a proto field. - // - "@uuid": generated UUID as hash key. - // - "@session": hash key from session (session sticky). - HashKey string `protobuf:"bytes,3,opt,name=hash_key,json=hashKey,proto3" json:"hash_key,omitempty"` - // If the client of this call come from third party. - // When this field is true, gateway will not check - // X-Source. - IsThirdParty bool `protobuf:"varint,4,opt,name=is_third_party,json=isThirdParty,proto3" json:"is_third_party,omitempty"` - // Used to call the GRPC service timeout. - // duration string, such as "300ms", "1m30s". - Timeout string `protobuf:"bytes,5,opt,name=timeout,proto3" json:"timeout,omitempty"` - // Api regist gateway. - ApiSource ApiSourceType `protobuf:"varint,6,opt,name=api_source,json=apiSource,proto3,enum=ease.api.ApiSourceType" json:"api_source,omitempty"` - // Auth token type. - TokenType AuthTokenType `protobuf:"varint,7,opt,name=token_type,json=tokenType,proto3,enum=ease.api.AuthTokenType" json:"token_type,omitempty"` - // Specified source Type. - SpecSourceType SpecSourceType `protobuf:"varint,8,opt,name=spec_source_type,json=specSourceType,proto3,enum=ease.api.SpecSourceType" json:"spec_source_type,omitempty"` + LoginNotRequired bool `protobuf:"varint,1,opt,name=login_not_required,json=loginNotRequired,proto3" json:"login_not_required,omitempty"` + ClientSignRequired bool `protobuf:"varint,2,opt,name=client_sign_required,json=clientSignRequired,proto3" json:"client_sign_required,omitempty"` + HashKey string `protobuf:"bytes,3,opt,name=hash_key,json=hashKey,proto3" json:"hash_key,omitempty"` + IsThirdParty bool `protobuf:"varint,4,opt,name=is_third_party,json=isThirdParty,proto3" json:"is_third_party,omitempty"` + Timeout string `protobuf:"bytes,5,opt,name=timeout,proto3" json:"timeout,omitempty"` + ApiSource ApiSourceType `protobuf:"varint,6,opt,name=api_source,json=apiSource,proto3,enum=ease.api.ApiSourceType" json:"api_source,omitempty"` + TokenType AuthTokenType `protobuf:"varint,7,opt,name=token_type,json=tokenType,proto3,enum=ease.api.AuthTokenType" json:"token_type,omitempty"` + SpecSourceType SpecSourceType `protobuf:"varint,8,opt,name=spec_source_type,json=specSourceType,proto3,enum=ease.api.SpecSourceType" json:"spec_source_type,omitempty"` } func (x *ApiMethod) Reset() { @@ -517,19 +475,16 @@ func (x *ApiMethod) GetSpecSourceType() SpecSourceType { return SpecSourceType_UNSPECIFIED } -// The service spec used for skylb/vexillary type ServiceSpec struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The identity of the service. - ServiceId data.ServiceId `protobuf:"varint,1,opt,name=service_id,json=serviceId,proto3,enum=data.ServiceId" json:"service_id,omitempty"` - // For skylb integration. - PortName string `protobuf:"bytes,2,opt,name=port_name,json=portName,proto3" json:"port_name,omitempty"` - Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` - GenController bool `protobuf:"varint,4,opt,name=gen_controller,json=genController,proto3" json:"gen_controller,omitempty"` - Balancer LoadBalancer `protobuf:"varint,5,opt,name=balancer,proto3,enum=ease.api.LoadBalancer" json:"balancer,omitempty"` + ServiceId data.ServiceId `protobuf:"varint,1,opt,name=service_id,json=serviceId,proto3,enum=data.ServiceId" json:"service_id,omitempty"` + PortName string `protobuf:"bytes,2,opt,name=port_name,json=portName,proto3" json:"port_name,omitempty"` + Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` + GenController bool `protobuf:"varint,4,opt,name=gen_controller,json=genController,proto3" json:"gen_controller,omitempty"` + Balancer LoadBalancer `protobuf:"varint,5,opt,name=balancer,proto3,enum=ease.api.LoadBalancer" json:"balancer,omitempty"` } func (x *ServiceSpec) Reset() { @@ -568,7 +523,7 @@ func (x *ServiceSpec) GetServiceId() data.ServiceId { if x != nil { return x.ServiceId } - return data.ServiceId_SERVICE_NONE + return data.ServiceId(0) } func (x *ServiceSpec) GetPortName() string { @@ -599,7 +554,6 @@ func (x *ServiceSpec) GetBalancer() LoadBalancer { return LoadBalancer_ROUND_ROBIN } -// ValidationRule defines the rule to validate the input value. type ValidationRule struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -671,7 +625,6 @@ func (x *ValidationRule) GetFunction() FunctionType { return FunctionType_FUNCTION_TYPE_UNKNOWN } -// ValidationRules holds a list of validation rules. type ValidationRules struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -721,7 +674,7 @@ func (x *ValidationRules) GetRules() []*ValidationRule { var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ { - ExtendedType: (*descriptor.MethodOptions)(nil), + ExtendedType: (*descriptorpb.MethodOptions)(nil), ExtensionType: (*HttpRule)(nil), Field: 108345, Name: "ease.api.http", @@ -729,7 +682,7 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ Filename: "httpoptions/annotations.proto", }, { - ExtendedType: (*descriptor.MethodOptions)(nil), + ExtendedType: (*descriptorpb.MethodOptions)(nil), ExtensionType: (*ApiMethod)(nil), Field: 108361, Name: "ease.api.method", @@ -737,7 +690,7 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ Filename: "httpoptions/annotations.proto", }, { - ExtendedType: (*descriptor.ServiceOptions)(nil), + ExtendedType: (*descriptorpb.ServiceOptions)(nil), ExtensionType: (*ServiceSpec)(nil), Field: 108349, Name: "ease.api.service_spec", @@ -745,7 +698,7 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ Filename: "httpoptions/annotations.proto", }, { - ExtendedType: (*descriptor.FieldOptions)(nil), + ExtendedType: (*descriptorpb.FieldOptions)(nil), ExtensionType: (*ValidationRules)(nil), Field: 108102, Name: "ease.api.rules", @@ -754,28 +707,22 @@ var file_httpoptions_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ }, } -// Extension fields to descriptor.MethodOptions. +// Extension fields to descriptorpb.MethodOptions. var ( - // See `HttpRule`. - // // optional ease.api.HttpRule http = 108345; E_Http = &file_httpoptions_annotations_proto_extTypes[0] // optional ease.api.ApiMethod method = 108361; E_Method = &file_httpoptions_annotations_proto_extTypes[1] ) -// Extension fields to descriptor.ServiceOptions. +// Extension fields to descriptorpb.ServiceOptions. var ( // optional ease.api.ServiceSpec service_spec = 108349; E_ServiceSpec = &file_httpoptions_annotations_proto_extTypes[2] ) -// Extension fields to descriptor.FieldOptions. +// Extension fields to descriptorpb.FieldOptions. var ( - // The validation rules, if there are more than - // one rules, validtion will pass only if all - // the rules are complied (AND). - // // optional ease.api.ValidationRules rules = 108102; E_Rules = &file_httpoptions_annotations_proto_extTypes[3] ) @@ -893,10 +840,14 @@ var file_httpoptions_annotations_proto_rawDesc = []byte{ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xc6, 0xcc, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x75, 0x6c, 0x65, 0x73, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x29, 0x0a, 0x0c, 0x63, + 0x75, 0x6c, 0x65, 0x73, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x67, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x10, 0x41, 0x6e, 0x6e, - 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0xa2, - 0x02, 0x04, 0x45, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, + 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xa2, 0x02, 0x04, + 0x45, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -914,22 +865,22 @@ func file_httpoptions_annotations_proto_rawDescGZIP() []byte { var file_httpoptions_annotations_proto_enumTypes = make([]protoimpl.EnumInfo, 7) var file_httpoptions_annotations_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_httpoptions_annotations_proto_goTypes = []interface{}{ - (ApiSourceType)(0), // 0: ease.api.ApiSourceType - (AuthTokenType)(0), // 1: ease.api.AuthTokenType - (SpecSourceType)(0), // 2: ease.api.SpecSourceType - (LoadBalancer)(0), // 3: ease.api.LoadBalancer - (OperatorType)(0), // 4: ease.api.OperatorType - (FunctionType)(0), // 5: ease.api.FunctionType - (ValueType)(0), // 6: ease.api.ValueType - (*ApiMethod)(nil), // 7: ease.api.ApiMethod - (*ServiceSpec)(nil), // 8: ease.api.ServiceSpec - (*ValidationRule)(nil), // 9: ease.api.ValidationRule - (*ValidationRules)(nil), // 10: ease.api.ValidationRules - (data.ServiceId)(0), // 11: data.ServiceId - (*descriptor.MethodOptions)(nil), // 12: google.protobuf.MethodOptions - (*descriptor.ServiceOptions)(nil), // 13: google.protobuf.ServiceOptions - (*descriptor.FieldOptions)(nil), // 14: google.protobuf.FieldOptions - (*HttpRule)(nil), // 15: ease.api.HttpRule + (ApiSourceType)(0), // 0: ease.api.ApiSourceType + (AuthTokenType)(0), // 1: ease.api.AuthTokenType + (SpecSourceType)(0), // 2: ease.api.SpecSourceType + (LoadBalancer)(0), // 3: ease.api.LoadBalancer + (OperatorType)(0), // 4: ease.api.OperatorType + (FunctionType)(0), // 5: ease.api.FunctionType + (ValueType)(0), // 6: ease.api.ValueType + (*ApiMethod)(nil), // 7: ease.api.ApiMethod + (*ServiceSpec)(nil), // 8: ease.api.ServiceSpec + (*ValidationRule)(nil), // 9: ease.api.ValidationRule + (*ValidationRules)(nil), // 10: ease.api.ValidationRules + (data.ServiceId)(0), // 11: data.ServiceId + (*descriptorpb.MethodOptions)(nil), // 12: google.protobuf.MethodOptions + (*descriptorpb.ServiceOptions)(nil), // 13: google.protobuf.ServiceOptions + (*descriptorpb.FieldOptions)(nil), // 14: google.protobuf.FieldOptions + (*HttpRule)(nil), // 15: ease.api.HttpRule } var file_httpoptions_annotations_proto_depIdxs = []int32{ 0, // 0: ease.api.ApiMethod.api_source:type_name -> ease.api.ApiSourceType diff --git a/httpoptions/http.pb.go b/httpoptions/http.pb.go old mode 100644 new mode 100755 index d644dbf..7b6ae47 --- a/httpoptions/http.pb.go +++ b/httpoptions/http.pb.go @@ -1,28 +1,12 @@ -// Copyright 2019 Google LLC. -// -// 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. -// See `https://github.com/googleapis/googleapis/blob/master/google/api/http.proto` - // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.23.0 -// protoc v3.12.3 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: httpoptions/http.proto -package ease_api +package annotations import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -36,29 +20,13 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -// Defines the HTTP configuration for an API service. It contains a list of -// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method -// to one or more HTTP REST API methods. type Http struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // A list of HTTP configuration rules that apply to individual API methods. - // - // **NOTE:** All service configuration rules follow "last one wins" order. - Rules []*HttpRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` - // When set to true, URL path parameters will be fully URI-decoded except in - // cases of single segment matches in reserved expansion, where "%2F" will be - // left encoded. - // - // The default behavior is to not decode RFC 6570 reserved characters in multi - // segment matches. - FullyDecodeReservedExpansion bool `protobuf:"varint,2,opt,name=fully_decode_reserved_expansion,json=fullyDecodeReservedExpansion,proto3" json:"fully_decode_reserved_expansion,omitempty"` + Rules []*HttpRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` + FullyDecodeReservedExpansion bool `protobuf:"varint,2,opt,name=fully_decode_reserved_expansion,json=fullyDecodeReservedExpansion,proto3" json:"fully_decode_reserved_expansion,omitempty"` } func (x *Http) Reset() { @@ -107,288 +75,12 @@ func (x *Http) GetFullyDecodeReservedExpansion() bool { return false } -// # gRPC Transcoding -// -// gRPC Transcoding is a feature for mapping between a gRPC method and one or -// more HTTP REST endpoints. It allows developers to build a single API service -// that supports both gRPC APIs and REST APIs. Many systems, including [Google -// APIs](https://github.com/googleapis/googleapis), -// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC -// Gateway](https://github.com/grpc-ecosystem/grpc-gateway), -// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature -// and use it for large scale production services. -// -// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies -// how different portions of the gRPC request message are mapped to the URL -// path, URL query parameters, and HTTP request body. It also controls how the -// gRPC response message is mapped to the HTTP response body. `HttpRule` is -// typically specified as an `google.api.http` annotation on the gRPC method. -// -// Each mapping specifies a URL path template and an HTTP method. The path -// template may refer to one or more fields in the gRPC request message, as long -// as each field is a non-repeated field with a primitive (non-message) type. -// The path template controls how fields of the request message are mapped to -// the URL path. -// -// Example: -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get: "/v1/{name=messages/*}" -// }; -// } -// } -// message GetMessageRequest { -// string name = 1; // Mapped to URL path. -// } -// message Message { -// string text = 1; // The resource content. -// } -// -// This enables an HTTP REST to gRPC mapping as below: -// -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` -// -// Any fields in the request message which are not bound by the path template -// automatically become HTTP query parameters if there is no HTTP request body. -// For example: -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get:"/v1/messages/{message_id}" -// }; -// } -// } -// message GetMessageRequest { -// message SubMessage { -// string subfield = 1; -// } -// string message_id = 1; // Mapped to URL path. -// int64 revision = 2; // Mapped to URL query parameter `revision`. -// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. -// } -// -// This enables a HTTP JSON to RPC mapping as below: -// -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | -// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: -// "foo"))` -// -// Note that fields which are mapped to URL query parameters must have a -// primitive type or a repeated primitive type or a non-repeated message type. -// In the case of a repeated type, the parameter can be repeated in the URL -// as `...?param=A¶m=B`. In the case of a message type, each field of the -// message is mapped to a separate parameter, such as -// `...?foo.a=A&foo.b=B&foo.c=C`. -// -// For HTTP methods that allow a request body, the `body` field -// specifies the mapping. Consider a REST update method on the -// message resource collection: -// -// service Messaging { -// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { -// option (google.api.http) = { -// patch: "/v1/messages/{message_id}" -// body: "message" -// }; -// } -// } -// message UpdateMessageRequest { -// string message_id = 1; // mapped to the URL -// Message message = 2; // mapped to the body -// } -// -// The following HTTP JSON to RPC mapping is enabled, where the -// representation of the JSON in the request body is determined by -// protos JSON encoding: -// -// HTTP | gRPC -// -----|----- -// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: -// "123456" message { text: "Hi!" })` -// -// The special name `*` can be used in the body mapping to define that -// every field not bound by the path template should be mapped to the -// request body. This enables the following alternative definition of -// the update method: -// -// service Messaging { -// rpc UpdateMessage(Message) returns (Message) { -// option (google.api.http) = { -// patch: "/v1/messages/{message_id}" -// body: "*" -// }; -// } -// } -// message Message { -// string message_id = 1; -// string text = 2; -// } -// -// -// The following HTTP JSON to RPC mapping is enabled: -// -// HTTP | gRPC -// -----|----- -// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: -// "123456" text: "Hi!")` -// -// Note that when using `*` in the body mapping, it is not possible to -// have HTTP parameters, as all fields not bound by the path end in -// the body. This makes this option more rarely used in practice when -// defining REST APIs. The common usage of `*` is in custom methods -// which don't use the URL at all for transferring data. -// -// It is possible to define multiple HTTP methods for one RPC by using -// the `additional_bindings` option. Example: -// -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get: "/v1/messages/{message_id}" -// additional_bindings { -// get: "/v1/users/{user_id}/messages/{message_id}" -// } -// }; -// } -// } -// message GetMessageRequest { -// string message_id = 1; -// string user_id = 2; -// } -// -// This enables the following two alternative HTTP JSON to RPC mappings: -// -// HTTP | gRPC -// -----|----- -// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` -// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: -// "123456")` -// -// ## Rules for HTTP mapping -// -// 1. Leaf request fields (recursive expansion nested messages in the request -// message) are classified into three categories: -// - Fields referred by the path template. They are passed via the URL path. -// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP -// request body. -// - All other fields are passed via the URL query parameters, and the -// parameter name is the field path in the request message. A repeated -// field can be represented as multiple query parameters under the same -// name. -// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields -// are passed via URL path and HTTP request body. -// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all -// fields are passed via URL path and URL query parameters. -// -// ### Path template syntax -// -// Template = "/" Segments [ Verb ] ; -// Segments = Segment { "/" Segment } ; -// Segment = "*" | "**" | LITERAL | Variable ; -// Variable = "{" FieldPath [ "=" Segments ] "}" ; -// FieldPath = IDENT { "." IDENT } ; -// Verb = ":" LITERAL ; -// -// The syntax `*` matches a single URL path segment. The syntax `**` matches -// zero or more URL path segments, which must be the last part of the URL path -// except the `Verb`. -// -// The syntax `Variable` matches part of the URL path as specified by its -// template. A variable template must not contain other variables. If a variable -// matches a single path segment, its template may be omitted, e.g. `{var}` -// is equivalent to `{var=*}`. -// -// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` -// contains any reserved character, such characters should be percent-encoded -// before the matching. -// -// If a variable contains exactly one path segment, such as `"{var}"` or -// `"{var=*}"`, when such a variable is expanded into a URL path on the client -// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The -// server side does the reverse decoding. Such variables show up in the -// [Discovery -// Document](https://developers.google.com/discovery/v1/reference/apis) as -// `{var}`. -// -// If a variable contains multiple path segments, such as `"{var=foo/*}"` -// or `"{var=**}"`, when such a variable is expanded into a URL path on the -// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. -// The server side does the reverse decoding, except "%2F" and "%2f" are left -// unchanged. Such variables show up in the -// [Discovery -// Document](https://developers.google.com/discovery/v1/reference/apis) as -// `{+var}`. -// -// ## Using gRPC API Service Configuration -// -// gRPC API Service Configuration (service config) is a configuration language -// for configuring a gRPC service to become a user-facing product. The -// service config is simply the YAML representation of the `google.api.Service` -// proto message. -// -// As an alternative to annotating your proto file, you can configure gRPC -// transcoding in your service config YAML files. You do this by specifying a -// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same -// effect as the proto annotation. This can be particularly useful if you -// have a proto that is reused in multiple services. Note that any transcoding -// specified in the service config will override any matching transcoding -// configuration in the proto. -// -// Example: -// -// http: -// rules: -// # Selects a gRPC method and applies HttpRule to it. -// - selector: example.v1.Messaging.GetMessage -// get: /v1/messages/{message_id}/{sub.subfield} -// -// ## Special notes -// -// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the -// proto to JSON conversion must follow the [proto3 -// specification](https://developers.google.com/protocol-buffers/docs/proto3#json). -// -// While the single segment variable follows the semantics of -// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String -// Expansion, the multi segment variable **does not** follow RFC 6570 Section -// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion -// does not expand special characters like `?` and `#`, which would lead -// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding -// for multi segment variables. -// -// The path variables **must not** refer to any repeated or mapped field, -// because client libraries are not capable of handling such variable expansion. -// -// The path variables **must not** capture the leading "/" character. The reason -// is that the most common use case "{var}" does not capture the leading "/" -// character. For consistency, all path variables must share the same behavior. -// -// Repeated message fields must not be mapped to URL query parameters, because -// no client library can support such complicated mapping. -// -// If an API needs to use a JSON array for request or response body, it can map -// the request or response body to a repeated field. However, some gRPC -// Transcoding implementations may not support this feature. type HttpRule struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Selects a method to which this rule applies. - // - // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. Selector string `protobuf:"bytes,1,opt,name=selector,proto3" json:"selector,omitempty"` - // Determines the URL pattern is matched by this rules. This pattern can be - // used with any of the {get|put|post|delete|patch} methods. A custom method - // can be defined using the 'custom' field. - // // Types that are assignable to Pattern: // *HttpRule_Get // *HttpRule_Put @@ -396,25 +88,10 @@ type HttpRule struct { // *HttpRule_Delete // *HttpRule_Patch // *HttpRule_Custom - Pattern isHttpRule_Pattern `protobuf_oneof:"pattern"` - // The name of the request field whose value is mapped to the HTTP request - // body, or `*` for mapping all request fields not captured by the path - // pattern to the HTTP body, or omitted for not having any HTTP request body. - // - // NOTE: the referred field must be present at the top-level of the request - // message type. - Body string `protobuf:"bytes,7,opt,name=body,proto3" json:"body,omitempty"` - // Optional. The name of the response field whose value is mapped to the HTTP - // response body. When omitted, the entire response message will be used - // as the HTTP response body. - // - // NOTE: The referred field must be present at the top-level of the response - // message type. - ResponseBody string `protobuf:"bytes,12,opt,name=response_body,json=responseBody,proto3" json:"response_body,omitempty"` - // Additional HTTP bindings for the selector. Nested bindings must - // not contain an `additional_bindings` field themselves (that is, - // the nesting may only be one level deep). - AdditionalBindings []*HttpRule `protobuf:"bytes,11,rep,name=additional_bindings,json=additionalBindings,proto3" json:"additional_bindings,omitempty"` + Pattern isHttpRule_Pattern `protobuf_oneof:"pattern"` + Body string `protobuf:"bytes,7,opt,name=body,proto3" json:"body,omitempty"` + ResponseBody string `protobuf:"bytes,12,opt,name=response_body,json=responseBody,proto3" json:"response_body,omitempty"` + AdditionalBindings []*HttpRule `protobuf:"bytes,11,rep,name=additional_bindings,json=additionalBindings,proto3" json:"additional_bindings,omitempty"` } func (x *HttpRule) Reset() { @@ -531,36 +208,26 @@ type isHttpRule_Pattern interface { } type HttpRule_Get struct { - // Maps to HTTP GET. Used for listing and getting information about - // resources. Get string `protobuf:"bytes,2,opt,name=get,proto3,oneof"` } type HttpRule_Put struct { - // Maps to HTTP PUT. Used for replacing a resource. Put string `protobuf:"bytes,3,opt,name=put,proto3,oneof"` } type HttpRule_Post struct { - // Maps to HTTP POST. Used for creating a resource or performing an action. Post string `protobuf:"bytes,4,opt,name=post,proto3,oneof"` } type HttpRule_Delete struct { - // Maps to HTTP DELETE. Used for deleting a resource. Delete string `protobuf:"bytes,5,opt,name=delete,proto3,oneof"` } type HttpRule_Patch struct { - // Maps to HTTP PATCH. Used for updating a resource. Patch string `protobuf:"bytes,6,opt,name=patch,proto3,oneof"` } type HttpRule_Custom struct { - // The custom pattern is used for specifying an HTTP method that is not - // included in the `pattern` field, such as HEAD, or "*" to leave the - // HTTP method unspecified for this rule. The wild-card rule is useful - // for services that provide content to Web (HTML) clients. Custom *CustomHttpPattern `protobuf:"bytes,8,opt,name=custom,proto3,oneof"` } @@ -576,15 +243,12 @@ func (*HttpRule_Patch) isHttpRule_Pattern() {} func (*HttpRule_Custom) isHttpRule_Pattern() {} -// A custom pattern is used for defining custom HTTP verb. type CustomHttpPattern struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The name of this custom HTTP verb. Kind string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"` - // The path matched by this custom verb. Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` } @@ -672,9 +336,13 @@ var file_httpoptions_http_proto_rawDesc = []byte{ 0x74, 0x70, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, - 0x68, 0x42, 0x25, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, - 0x69, 0x42, 0x09, 0x48, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0xf8, 0x01, - 0x01, 0xa2, 0x02, 0x04, 0x45, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x68, 0x42, 0x63, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x61, 0x73, 0x65, 0x2e, 0x61, 0x70, + 0x69, 0x42, 0x09, 0x48, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xf8, 0x01, 0x01, 0xa2, + 0x02, 0x04, 0x45, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..b731f05 --- /dev/null +++ b/renovate.json @@ -0,0 +1,53 @@ +{ + "extends": [ + "config:base" + ], + "baseBranches": [ + "v1", + "master" + ], + "postUpdateOptions": [ + "gomodTidy" + ], + "packageRules": [ + { + "updateTypes": [ + "minor", + "patch", + "pin", + "digest" + ], + "automerge": true + }, + { + "baseBranchList": [ + "v1" + ], + "packageNames": [ + "github.com/golang/protobuf", + "google.golang.org/genproto", + "io_bazel_rules_go", + "golang.org/x/oauth2", + "google.golang.org/grpc" + ], + "enabled": false + }, + { + "baseBranchList": [ + "master" + ], + "packageNames": [ + "github.com/golang/protobuf", + "google.golang.org/protobuf" + ], + "groupName": "golang/protobuf" + }, + { + "packagePatterns": [ + "jekyll.*", + "github-pages" + ], + "enabled": false + } + ] +} diff --git a/repositories.bzl b/repositories.bzl index 421c22b..2c22a00 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -4,8 +4,8 @@ def go_repositories(): go_repository( name = "com_github_binchencoder_letsgo", importpath = "github.com/binchencoder/letsgo", - sum = "h1:hEDDOeGdX9R/JPYMdVo9N/9iQa5BeBLluTssrNYy/ng=", - version = "v0.0.3", + sum = "h1:wYZv8TO4TGO2U8HjEO5Odf8OYWQjfrXS8ddfGZWQfHI=", + version = "v0.0.5", ) go_repository( name = "com_github_binchencoder_skylb_api", @@ -23,8 +23,8 @@ def go_repositories(): go_repository( name = "com_github_grpc_ecosystem_grpc_gateway", importpath = "github.com/grpc-ecosystem/grpc-gateway/v2", - sum = "h1:X2vfSnm1WC8HEo0MBHZg2TcuDUHJj6kd1TmEAQncnSA=", - version = "v2.0.1", + sum = "h1:SLkFeyLhrg86Ny5Wme4MGGace7EHfgsb07uWX/QUGEQ=", + version = "v2.9.0", ) go_repository( name = "com_github_grpc_ecosystem_grpc_opentracing", @@ -53,8 +53,8 @@ def go_repositories(): go_repository( name = "com_github_fatih_color", importpath = "github.com/fatih/color", - sum = "h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=", - version = "v1.9.0", + sum = "h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=", + version = "v1.7.0", ) go_repository( name = "com_github_ghodss_yaml", @@ -65,26 +65,26 @@ def go_repositories(): go_repository( name = "com_github_golang_glog", importpath = "github.com/golang/glog", - sum = "h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=", - version = "v0.0.0-20160126235308-23def4e6c14b", + sum = "h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=", + version = "v1.0.0", ) go_repository( name = "com_github_golang_protobuf", importpath = "github.com/golang/protobuf", - sum = "h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=", - version = "v1.4.2", + sum = "h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=", + version = "v1.5.2", ) go_repository( name = "com_github_google_uuid", importpath = "github.com/google/uuid", - sum = "h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=", - version = "v1.1.1", + sum = "h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=", + version = "v1.1.2", ) go_repository( name = "com_github_google_go_cmp", importpath = "github.com/google/go-cmp", - sum = "h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=", - version = "v0.5.0", + sum = "h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=", + version = "v0.5.7", ) go_repository( name = "com_github_klauspost_cpuid", @@ -131,8 +131,8 @@ def go_repositories(): go_repository( name = "com_github_klauspost_compress", importpath = "github.com/klauspost/compress", - sum = "h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I=", - version = "v1.10.10", + sum = "h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=", + version = "v1.11.7", ) go_repository( name = "com_github_opentracing_opentracing_go", @@ -141,7 +141,7 @@ def go_repositories(): version = "v1.2.0", ) go_repository( - name = "com_github_matttproud_golang_protobuf_extension", + name = "com_github_matttproud_golang_protobuf_extensions", importpath = "github.com/matttproud/golang_protobuf_extensions", sum = "h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=", version = "v1.0.1", @@ -149,8 +149,8 @@ def go_repositories(): go_repository( name = "com_github_stretchr_testify", importpath = "github.com/stretchr/testify", - sum = "h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=", - version = "v1.6.1", + sum = "h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=", + version = "v1.7.0", ) go_repository( name = "com_github_soheilhy_cmux", @@ -204,8 +204,8 @@ def go_repositories(): go_repository( name = "in_gopkg_yaml_v2", importpath = "gopkg.in/yaml.v2", - sum = "h1:uUkhRGrsEyx/laRdeS6YIQKIys8pg+lRSRdVMTYjivs=", - version = "v2.0.0", + sum = "h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=", + version = "v2.4.0", ) go_repository( name = "in_gopkg_yaml_v3", @@ -213,37 +213,54 @@ def go_repositories(): sum = "h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=", version = "v3.0.0-20200615113413-eeeca48fe776", ) + go_repository( + name = "io_etcd_go_bbolt", + importpath = "go.etcd.io/bbolt", + sum = "h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=", + version = "v1.3.2", + ) + go_repository( + name = "io_k8s_sigs_yaml", + importpath = "sigs.k8s.io/yaml", + sum = "h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=", + version = "v1.3.0", + ) go_repository( name = "org_golang_google_genproto", importpath = "google.golang.org/genproto", - sum = "h1:7RoRaOmOAXwqnurgQ5g5/d0yCi9ha2UxuTZULXudK7A=", - version = "v0.0.0-20201028140639-c77dae4b0522", + sum = "h1:ErU+UA6wxadoU8nWrsy5MZUVBs75K17zUCsUCIfrXCE=", + version = "v0.0.0-20220314164441-57ef72a4c106", ) go_repository( name = "org_golang_google_grpc", importpath = "google.golang.org/grpc", - sum = "h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=", - version = "v1.29.1", + sum = "h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=", + version = "v1.45.0", ) - + # go_repository( + # name = "org_golang_google_grpc", + # importpath = "google.golang.org/grpc", + # sum = "h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=", + # version = "v1.29.1", + # ) go_repository( name = "org_golang_google_grpc_cmd_protoc_gen_go_grpc", importpath = "google.golang.org/grpc/cmd/protoc-gen-go-grpc", - sum = "h1:KNluVV5ay+orsSPJ6XTpwJQ8qBhrBkOTmtBFGeDlBcY=", - version = "v0.0.0-20200527211525-6c9e30c09db2", + sum = "h1:lQ+dE99pFsb8osbJB3oRfE5eW4Hx6a/lZQr8Jh+eoT4=", + version = "v1.0.0", ) go_repository( name = "org_golang_google_protobuf", importpath = "google.golang.org/protobuf", - sum = "h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=", - version = "v1.25.0", + sum = "h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=", + version = "v1.27.1", ) go_repository( name = "org_uber_go_atomic", importpath = "go.uber.org/atomic", - sum = "h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=", - version = "v1.6.0", + sum = "h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=", + version = "v1.7.0", ) go_repository( name = "org_golang_x_crypto", @@ -286,14 +303,14 @@ def go_repositories(): go_repository( name = "org_golang_x_net", importpath = "golang.org/x/net", - sum = "h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=", - version = "v0.0.0-20200822124328-c89045814202", + sum = "h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=", + version = "v0.0.0-20220127200216-cd36cc0744dd", ) go_repository( name = "org_golang_x_oauth2", importpath = "golang.org/x/oauth2", - sum = "h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=", - version = "v0.0.0-20200902213428-5d25da1a8d43", + sum = "h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM=", + version = "v0.0.0-20220309155454-6242fa91716a", ) go_repository( name = "org_golang_x_sync", @@ -304,14 +321,21 @@ def go_repositories(): go_repository( name = "org_golang_x_sys", importpath = "golang.org/x/sys", - sum = "h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw=", - version = "v0.0.0-20200803210538-64077c9b5642", + sum = "h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=", + version = "v0.0.0-20211216021012-1d35b9e2eb4e", ) + go_repository( + name = "org_golang_x_term", + importpath = "golang.org/x/term", + sum = "h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=", + version = "v0.0.0-20210927222741-03fcf44c2211", + ) + go_repository( name = "org_golang_x_text", importpath = "golang.org/x/text", - sum = "h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=", - version = "v0.3.3", + sum = "h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=", + version = "v0.3.7", ) go_repository( From efb0fd0ac1dfbbf0fc7160d9ee32eb3e05fae11b Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sun, 27 Mar 2022 16:03:43 +0800 Subject: [PATCH 2/5] Upgrade github.com/grpc-ecosystem/grpc-gateway version to v2.9.0 --- WORKSPACE | 18 +- cmd/custom-gateway/BUILD.bazel | 4 +- cmd/gateway/BUILD.bazel | 6 +- cmd/gateway/registryprod.go | 2 +- .../cmd => }/grpc-server/BUILD.bazel | 6 +- .../{internal/cmd => }/grpc-server/echo.go | 10 +- .../{internal/cmd => }/grpc-server/main.go | 4 +- examples/internal/README.md | 24 +- .../internal/cmd/example-grpc-server/main.go | 33 +- examples/internal/gateway/BUILD.bazel | 15 +- examples/internal/integration/BUILD.bazel | 27 +- .../internal/integration/integration_test.go | 262 +++--- examples/internal/proto/examplepb/BUILD.bazel | 15 +- .../proto/examplepb/echo_service.pb.go | 753 ++++++++++++++++++ .../proto/examplepb}/echo_service.pb.gw.go | 449 ++++++++--- .../proto/examplepb/echo_service_grpc.pb.go | 239 ++++++ .../proto/examplepb/generated_input.proto | 20 + .../examplepb/generated_input.swagger.json | 347 ++++++++ .../standalone_echo_service.buf.gen.yaml | 8 + ...vice.yaml => unannotated_echo_servic.yaml} | 0 .../unannotated_echo_service.buf.gen.yaml | 12 + .../examplepb/unannotated_echo_service.pb.go | 437 ++++++++++ .../unannotated_echo_service.pb.gw.go | 3 + .../unannotated_echo_service.swagger.yaml | 112 +++ .../unannotated_echo_service_grpc.pb.go | 167 ++++ examples/internal/server/BUILD.bazel | 32 +- examples/internal/server/echo.go | 2 +- examples/internal/server/main.go | 4 +- .../internal/gengateway/generator.go | 19 +- .../internal/gengateway/template.go | 25 +- gateway/runtime/BUILD.bazel | 8 +- gateway/runtime/mux_test.go | 2 +- go.mod | 5 +- go.sum | 108 +-- integrate/BUILD.bazel | 4 +- proto/{examples => examplepb}/BUILD.bazel | 26 +- .../echo_service.proto | 6 +- .../echo_service.swagger.json | 0 proto/{examples => examplepb}/pom.xml | 0 proto/examples/echo_service.pb.go | 425 ---------- proto/examples/echo_service_grpc.pb.go | 158 ---- repositories.bzl | 240 ++++-- 42 files changed, 2908 insertions(+), 1129 deletions(-) rename examples/{internal/cmd => }/grpc-server/BUILD.bazel (83%) rename examples/{internal/cmd => }/grpc-server/echo.go (60%) rename examples/{internal/cmd => }/grpc-server/main.go (85%) create mode 100755 examples/internal/proto/examplepb/echo_service.pb.go rename {proto/examples => examples/internal/proto/examplepb}/echo_service.pb.gw.go (70%) create mode 100755 examples/internal/proto/examplepb/echo_service_grpc.pb.go create mode 100644 examples/internal/proto/examplepb/generated_input.proto create mode 100644 examples/internal/proto/examplepb/generated_input.swagger.json create mode 100644 examples/internal/proto/examplepb/standalone_echo_service.buf.gen.yaml rename examples/internal/proto/examplepb/{unannotated_echo_service.yaml => unannotated_echo_servic.yaml} (100%) create mode 100644 examples/internal/proto/examplepb/unannotated_echo_service.buf.gen.yaml create mode 100755 examples/internal/proto/examplepb/unannotated_echo_service.pb.go create mode 100755 examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go create mode 100644 examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml create mode 100755 examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go rename proto/{examples => examplepb}/BUILD.bazel (79%) rename proto/{examples => examplepb}/echo_service.proto (95%) rename proto/{examples => examplepb}/echo_service.swagger.json (100%) rename proto/{examples => examplepb}/pom.xml (100%) delete mode 100755 proto/examples/echo_service.pb.go delete mode 100755 proto/examples/echo_service_grpc.pb.go diff --git a/WORKSPACE b/WORKSPACE index 796ce44..bf71513 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -6,9 +6,9 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") # Define before rules_proto, otherwise we receive the version of com_google_protobuf from there http_archive( name = "com_google_protobuf", - sha256 = "3bd7828aa5af4b13b99c191e8b1e884ebfa9ad371b0ce264605d347f135d2568", - strip_prefix = "protobuf-3.19.4", - urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.19.4.tar.gz"], + sha256 = "b07772d38ab07e55eca4d50f4b53da2d998bb221575c60a4f81100242d4b4889", + strip_prefix = "protobuf-3.20.0", + urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.20.0.tar.gz"], ) http_archive( @@ -42,10 +42,10 @@ rules_proto_toolchains() http_archive( name = "io_bazel_rules_go", - sha256 = "d6b2513456fe2229811da7eb67a444be7785f5323c6708b38d851d2b51e54d83", + sha256 = "f2dcd210c7095febe54b804bb1cd3a58fe8435a909db2ec04e31542631cf715c", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.30.0/rules_go-v0.30.0.zip", - "https://github.com/bazelbuild/rules_go/releases/download/v0.30.0/rules_go-v0.30.0.zip", + "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.31.0/rules_go-v0.31.0.zip", + "https://github.com/bazelbuild/rules_go/releases/download/v0.31.0/rules_go-v0.31.0.zip", ], ) @@ -64,9 +64,9 @@ http_archive( # https://github.com/bazelbuild/bazel-gazelle/pull/1194 is merged git_repository( name = "bazel_gazelle", - commit = "4a1aeae7cab962fd8088f42038d3a477cdca91a5", - remote = "https://github.com/johanbrandhorst/bazel-gazelle", - shallow_since = "1647116890 +0000", + commit = "f377e6eff8e24508feb1a34b1e5e681982482a9f", + remote = "https://github.com/bazelbuild/bazel-gazelle", + shallow_since = "1648046534 -0400", ) # 从下载的扩展里载入 go_rules_dependencies go_register_toolchains 函数 diff --git a/cmd/custom-gateway/BUILD.bazel b/cmd/custom-gateway/BUILD.bazel index 3215f79..2d65430 100644 --- a/cmd/custom-gateway/BUILD.bazel +++ b/cmd/custom-gateway/BUILD.bazel @@ -15,8 +15,8 @@ go_library( ], importpath = "github.com/binchencoder/ease-gateway/cmd/custom-gateway", deps = [ - "//examples/internal/proto/examplepb:go_default_library", - "//gateway/runtime:go_default_library", + "//examples/internal/proto/examplepb", + "//gateway/runtime", "//integrate:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_letsgo//:go_default_library", diff --git a/cmd/gateway/BUILD.bazel b/cmd/gateway/BUILD.bazel index b7a3a43..494226f 100644 --- a/cmd/gateway/BUILD.bazel +++ b/cmd/gateway/BUILD.bazel @@ -10,14 +10,14 @@ go_library( importpath = "github.com/binchencoder/ease-gateway/cmd/gateway", visibility = ["//visibility:public"], deps = [ - "//gateway/runtime:go_default_library", + "//proto/examplepb", + "//gateway/runtime", "//integrate:go_default_library", - "//proto/examples:go_default_library", "//util:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_letsgo//:go_default_library", "@com_github_binchencoder_letsgo//service/naming:go_default_library", - "@com_github_golang_glog//:go_default_library", + "@com_github_golang_glog//:glog", ], ) diff --git a/cmd/gateway/registryprod.go b/cmd/gateway/registryprod.go index fc761a6..bd4c0cf 100755 --- a/cmd/gateway/registryprod.go +++ b/cmd/gateway/registryprod.go @@ -2,5 +2,5 @@ package main // Import so that applications register themselves to gateway. import ( - _ "github.com/binchencoder/ease-gateway/proto/examples" + _ "github.com/binchencoder/ease-gateway/proto/examplepb" ) diff --git a/examples/internal/cmd/grpc-server/BUILD.bazel b/examples/grpc-server/BUILD.bazel similarity index 83% rename from examples/internal/cmd/grpc-server/BUILD.bazel rename to examples/grpc-server/BUILD.bazel index 493438a..4c9fcd7 100644 --- a/examples/internal/cmd/grpc-server/BUILD.bazel +++ b/examples/grpc-server/BUILD.bazel @@ -8,12 +8,12 @@ go_library( "main.go", "echo.go", ], - importpath = "github.com/binchencoder/ease-gateway/examples/internal/cmd/custom-grpc-server", + importpath = "github.com/binchencoder/ease-gateway/examples/grpc-server", deps = [ - "//proto/examples:go_default_library", + "//proto/examplepb", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_skylb_api//server:go_default_library", - "@com_github_golang_glog//:go_default_library", + "@com_github_golang_glog//:glog", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//metadata:go_default_library", ], diff --git a/examples/internal/cmd/grpc-server/echo.go b/examples/grpc-server/echo.go similarity index 60% rename from examples/internal/cmd/grpc-server/echo.go rename to examples/grpc-server/echo.go index ccb99b5..181a464 100644 --- a/examples/internal/cmd/grpc-server/echo.go +++ b/examples/grpc-server/echo.go @@ -3,7 +3,7 @@ package main import ( "context" - examples "github.com/binchencoder/ease-gateway/proto/examples" + "github.com/binchencoder/ease-gateway/proto/examplepb" "github.com/golang/glog" "google.golang.org/grpc" "google.golang.org/grpc/metadata" @@ -14,16 +14,16 @@ import ( type echoServer struct{} // NewEchoServer new echo server -func NewEchoServer() examples.EchoServiceServer { +func NewEchoServer() examplepb.EchoServiceServer { return new(echoServer) } -func (s *echoServer) Echo(ctx context.Context, msg *examples.SimpleMessage) (*examples.SimpleMessage, error) { +func (s *echoServer) Echo(ctx context.Context, msg *examplepb.SimpleMessage) (*examplepb.SimpleMessage, error) { glog.Info(msg) return msg, nil } -func (s *echoServer) EchoBody(ctx context.Context, msg *examples.SimpleMessage) (*examples.SimpleMessage, error) { +func (s *echoServer) EchoBody(ctx context.Context, msg *examplepb.SimpleMessage) (*examplepb.SimpleMessage, error) { glog.Info(msg) grpc.SendHeader(ctx, metadata.New(map[string]string{ "foo": "foo1", @@ -36,7 +36,7 @@ func (s *echoServer) EchoBody(ctx context.Context, msg *examples.SimpleMessage) return msg, nil } -func (s *echoServer) EchoDelete(ctx context.Context, msg *examples.SimpleMessage) (*examples.SimpleMessage, error) { +func (s *echoServer) EchoDelete(ctx context.Context, msg *examplepb.SimpleMessage) (*examplepb.SimpleMessage, error) { glog.Info(msg) return msg, nil } diff --git a/examples/internal/cmd/grpc-server/main.go b/examples/grpc-server/main.go similarity index 85% rename from examples/internal/cmd/grpc-server/main.go rename to examples/grpc-server/main.go index e4e6369..5b07a39 100644 --- a/examples/internal/cmd/grpc-server/main.go +++ b/examples/grpc-server/main.go @@ -8,7 +8,7 @@ import ( "flag" "fmt" - examples "github.com/binchencoder/ease-gateway/proto/examples" + examplepb "github.com/binchencoder/ease-gateway/proto/examplepb" "github.com/binchencoder/gateway-proto/data" skylb "github.com/binchencoder/skylb-api/server" "github.com/golang/glog" @@ -29,7 +29,7 @@ func main() { skylb.Register(data.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc", *port) skylb.EnableHistogram() skylb.Start(fmt.Sprintf(":%d", *port), func(s *grpc.Server) error { - examples.RegisterEchoServiceServer(s, NewEchoServer()) + examplepb.RegisterEchoServiceServer(s, NewEchoServer()) return nil }) } diff --git a/examples/internal/README.md b/examples/internal/README.md index d46322b..59660c2 100644 --- a/examples/internal/README.md +++ b/examples/internal/README.md @@ -1,43 +1,43 @@ # Overrview -ease-gateway/examples 是使用ease-gateway的一个完整示例,包含gateway-server 和 gRPC-server. 还有Java实现gRPC Server的例子 [https://github.com/binchencoder/spring-boot-grpc/tree/master/spring-boot-grpc-examples] +ease-gateway/examples/internal 是使用ease-gateway的一个完整示例,包含gateway-server 和 gRPC-server. 还有Java实现gRPC Server的例子 [https://github.com/binchencoder/spring-boot-grpc/tree/master/spring-boot-grpc-examples] # Build the example build gateway server ``` -bazel build ease-gateway/examples/cmd/example-gateway-server/... +bazel build examples/internal/cmd/example-gateway-server/... ``` build gRPC server ``` -bazel build ease-gateway/examples/cmd/example-grpc-server/... +bazel build examples/internal/cmd/example-grpc-server/... ``` # Run the example start gateway server -``` -ease-gateway/bazel-bin/examples/cmd/example-gateway-server/example-gateway-server_/example-gateway-server -skylb-endpoints="127.0.0.1:1900" -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 +```shell +ease-gateway/bazel-bin/examples/internal/cmd/example-gateway-server/example-gateway-server_/example-gateway-server -skylb-endpoints="127.0.0.1:1900" -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 ``` start custom-gateway server -``` +```shell ease-gateway/bazel-bin/cmd/custom-gateway/custom-ease-gateway_/custom-ease-gateway -skylb-endpoints="127.0.0.1:1900" -debug-service=custom-ease-gateway-test -debug-svc-endpoint=custom-ease-gateway-test=localhost:9090 ``` -start examples gRPC server for test //examples/cmd/example-gateway-server -``` -ease-gateway/bazel-bin/examples/cmd/example-grpc-server/example-grpc-server_/example-grpc-server +start examples gRPC server for test //examples/internal/cmd/example-grpc-server +```shell +ease-gateway/bazel-bin/examples/internal/cmd/example-grpc-server/example-grpc-server_/example-grpc-server -skylb-endpoints="127.0.0.1:1900,127.0.0.1:1901" ``` start gRPC server for test //cmd/gateway -``` -ease-gateway/bazel-bin/examples/cmd/grpc-server/grpc-server_/grpc-server -skylb-endpoints="127.0.0.1:1900" +```shell +ease-gateway/bazel-bin/examples/grpc-server/grpc-server_/grpc-server -skylb-endpoints="127.0.0.1:1900" ``` start //cmd/gateway -``` +```shell ease-gateway/bazel-bin/cmd/gateway/gateway_/gateway -skylb-endpoints="127.0.0.1:1900" -v=2 -log_dir=. ``` diff --git a/examples/internal/cmd/example-grpc-server/main.go b/examples/internal/cmd/example-grpc-server/main.go index 79d17b0..1482ee4 100644 --- a/examples/internal/cmd/example-grpc-server/main.go +++ b/examples/internal/cmd/example-grpc-server/main.go @@ -5,14 +5,17 @@ package main import ( - "context" "flag" + "fmt" + + examplepb "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" + + "github.com/binchencoder/gateway-proto/data" + skylb "github.com/binchencoder/skylb-api/server" - // examples "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb" "github.com/binchencoder/ease-gateway/examples/internal/server" - // "github.com/binchencoder/gateway-proto/data" - // skylb "github.com/binchencoder/skylb-api/server" "github.com/golang/glog" + "google.golang.org/grpc" ) var ( @@ -27,15 +30,15 @@ func main() { defer glog.Flush() // Don't regist to skylbserver - ctx := context.Background() - if err := server.Run(ctx, *network, *addr); err != nil { - glog.Fatal(err) - } - - // skylb.Register(data.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc", *port) - // skylb.EnableHistogram() - // skylb.Start(fmt.Sprintf(":%d", *port), func(s *grpc.Server) error { - // examples.RegisterEchoServiceServer(s, server.NewEchoServer()) - // return nil - // }) + // ctx := context.Background() + // if err := server.Run(ctx, *network, *addr); err != nil { + // glog.Fatal(err) + // } + + skylb.Register(data.ServiceId_CUSTOM_EASE_GATEWAY_TEST, "grpc", *port) + skylb.EnableHistogram() + skylb.Start(fmt.Sprintf(":%d", *port), func(s *grpc.Server) error { + examplepb.RegisterEchoServiceServer(s, server.NewEchoServer()) + return nil + }) } diff --git a/examples/internal/gateway/BUILD.bazel b/examples/internal/gateway/BUILD.bazel index d0712e2..5739512 100644 --- a/examples/internal/gateway/BUILD.bazel +++ b/examples/internal/gateway/BUILD.bazel @@ -1,7 +1,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( - name = "go_default_library", + name = "gateway", srcs = [ "doc.go", "gateway.go", @@ -11,11 +11,18 @@ go_library( importpath = "github.com/binchencoder/ease-gateway/examples/internal/gateway", visibility = ["//visibility:public"], deps = [ - "//examples/internal/proto/examplepb:go_default_library", - "//gateway/runtime:go_default_library", + "//examples/internal/proto/examplepb", + "//gateway/runtime", "//util:go_default_library", "@com_github_golang_glog//:go_default_library", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//connectivity:go_default_library", + "@org_golang_google_grpc//connectivity", + "@org_golang_google_grpc//credentials/insecure", ], ) + +alias( + name = "go_default_library", + actual = ":gateway", + visibility = ["//examples:__subpackages__"], +) diff --git a/examples/internal/integration/BUILD.bazel b/examples/internal/integration/BUILD.bazel index 6931ba2..03c89f4 100644 --- a/examples/internal/integration/BUILD.bazel +++ b/examples/internal/integration/BUILD.bazel @@ -1,27 +1,26 @@ load("@io_bazel_rules_go//go:def.bzl", "go_test") go_test( - name = "go_default_test", + name = "integration_test", srcs = [ "integration_test.go", "main_test.go", ], deps = [ - "//examples/internal/gateway:go_default_library", - "//examples/internal/proto/examplepb:go_default_library", - # "//examples/internal/proto/examplepb:unannotated_go_default_library", - "//examples/internal/server:go_default_library", - "//gateway/runtime:go_default_library", + "//examples/internal/gateway", + "//examples/internal/proto/examplepb", + "//examples/internal/server", + "//gateway/runtime", "//httpoptions", - "@com_github_golang_glog//:go_default_library", - "@com_github_google_go_cmp//cmp:go_default_library", + "@com_github_golang_glog//:glog", + "@com_github_google_go_cmp//cmp", "@go_googleapis//google/rpc:status_go_proto", - "@io_bazel_rules_go//proto/wkt:empty_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_protobuf//encoding/protojson:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//testing/protocmp:go_default_library", - "@org_golang_google_protobuf//types/known/structpb:go_default_library", + "@org_golang_google_grpc//codes", + "@org_golang_google_protobuf//encoding/protojson", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//testing/protocmp", + "@org_golang_google_protobuf//types/known/emptypb", + "@org_golang_google_protobuf//types/known/structpb", ], ) diff --git a/examples/internal/integration/integration_test.go b/examples/internal/integration/integration_test.go index daa5486..d43092d 100644 --- a/examples/internal/integration/integration_test.go +++ b/examples/internal/integration/integration_test.go @@ -13,6 +13,8 @@ import ( "github.com/binchencoder/ease-gateway/gateway/runtime" "github.com/google/go-cmp/cmp" fieldmaskpb "google.golang.org/genproto/protobuf/field_mask" + + // "google.golang.org/grpc/codes" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" @@ -33,9 +35,11 @@ func TestEcho(t *testing.T) { testEchoOneof(t, 8088, apiPrefix, "application/json") testEchoOneof1(t, 8088, apiPrefix, "application/json") testEchoOneof2(t, 8088, apiPrefix, "application/json") - testEchoBody(t, 8088, apiPrefix) + testEchoBody(t, 8088, apiPrefix, true) + testEchoBody(t, 8088, apiPrefix, false) // Use SendHeader/SetTrailer without gRPC server https://github.com/grpc-ecosystem/grpc-gateway/issues/517#issuecomment-684625645 - testEchoBody(t, 8089, apiPrefix) + testEchoBody(t, 8089, apiPrefix, true) + testEchoBody(t, 8089, apiPrefix, false) }) } t.Run("testEchoValidationRules", func(t *testing.T) { @@ -55,9 +59,12 @@ func TestEchoPatch(t *testing.T) { StructValue: &structpb.Struct{Fields: map[string]*structpb.Value{ "layered_struct_key": {Kind: &structpb.Value_StringValue{StringValue: "struct_val"}}, }}, - }}}}, - ValueField: &structpb.Value{Kind: &structpb.Value_StructValue{StructValue: &structpb.Struct{Fields: map[string]*structpb.Value{ - "value_struct_key": {Kind: &structpb.Value_StringValue{StringValue: "value_struct_val"}}}}, + }}, + }}, + ValueField: &structpb.Value{Kind: &structpb.Value_StructValue{ + StructValue: &structpb.Struct{Fields: map[string]*structpb.Value{ + "value_struct_key": {Kind: &structpb.Value_StringValue{StringValue: "value_struct_val"}}, + }}, }}, } payload, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(&sent) @@ -135,6 +142,39 @@ func TestForwardResponseOption(t *testing.T) { testEcho(t, port, "v1", "application/vnd.docker.plugins.v1.1+json") } +func TestForwardResponseOptionHTTPPathPattern(t *testing.T) { + if testing.Short() { + t.Skip() + return + } + + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + port := 7080 + go func() { + if err := runGateway( + ctx, + fmt.Sprintf(":%d", port), + runtime.WithForwardResponseOption( + func(ctx context.Context, w http.ResponseWriter, _ proto.Message) error { + path, _ := runtime.HTTPPathPattern(ctx) + w.Header().Set("Content-Type", path) + return nil + }, + ), + ); err != nil { + t.Errorf("runGateway() failed with %v; want success", err) + return + } + }() + if err := waitForGateway(ctx, uint16(port)); err != nil { + t.Errorf("waitForGateway(ctx, %d) failed with %v; want success", port, err) + } + testEcho(t, port, "v1", "/v1/example/echo/{id}") +} + func testEcho(t *testing.T, port int, apiPrefix string, contentType string) { apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo/myid", port, apiPrefix) resp, err := http.Post(apiURL, "application/json", strings.NewReader("{}")) @@ -149,39 +189,18 @@ func testEcho(t *testing.T, port int, apiPrefix string, contentType string) { return } - if apiPrefix != "v1" { - if got, want := resp.StatusCode, http.StatusNotFound; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } else { - if got, want := resp.StatusCode, http.StatusOK; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.Id, "myid"; got != want { - t.Errorf("msg.Id = %q; want %q", got, want) - } - - if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { - t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) - } - if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { - t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) - } + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } - if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want { - t.Errorf("Grpc-Trailer-Foo was %q, wanted %q", got, want) - } - if got, want := resp.Trailer.Get("Grpc-Trailer-Bar"), "bar2"; got != want { - t.Errorf("Grpc-Trailer-Bar was %q, wanted %q", got, want) - } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.Id, "myid"; got != want { + t.Errorf("msg.Id = %q; want %q", got, want) } if value := resp.Header.Get("Content-Type"); value != contentType { @@ -203,25 +222,18 @@ func testEchoOneof(t *testing.T, port int, apiPrefix string, contentType string) return } - if apiPrefix != "v1" { - if got, want := resp.StatusCode, http.StatusNotFound; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } else { - if got, want := resp.StatusCode, http.StatusOK; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.GetLang(), "golang"; got != want { - t.Errorf("msg.GetLang() = %q; want %q", got, want) - } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetLang(), "golang"; got != want { + t.Errorf("msg.GetLang() = %q; want %q", got, want) } if value := resp.Header.Get("Content-Type"); value != contentType { @@ -243,25 +255,18 @@ func testEchoOneof1(t *testing.T, port int, apiPrefix string, contentType string return } - if apiPrefix != "v1" { - if got, want := resp.StatusCode, http.StatusNotFound; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } else { - if got, want := resp.StatusCode, http.StatusOK; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.GetStatus().GetNote(), "golang"; got != want { - t.Errorf("msg.GetStatus().GetNote() = %q; want %q", got, want) - } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetStatus().GetNote(), "golang"; got != want { + t.Errorf("msg.GetStatus().GetNote() = %q; want %q", got, want) } if value := resp.Header.Get("Content-Type"); value != contentType { @@ -283,25 +288,18 @@ func testEchoOneof2(t *testing.T, port int, apiPrefix string, contentType string return } - if apiPrefix != "v1" { - if got, want := resp.StatusCode, http.StatusNotFound; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } else { - if got, want := resp.StatusCode, http.StatusOK; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } - msg := new(examplepb.UnannotatedSimpleMessage) - if err := marshaler.Unmarshal(buf, msg); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if got, want := msg.GetNo().GetNote(), "golang"; got != want { - t.Errorf("msg.GetNo().GetNote() = %q; want %q", got, want) - } + msg := new(examplepb.UnannotatedSimpleMessage) + if err := marshaler.Unmarshal(buf, msg); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if got, want := msg.GetNo().GetNote(), "golang"; got != want { + t.Errorf("msg.GetNo().GetNote() = %q; want %q", got, want) } if value := resp.Header.Get("Content-Type"); value != contentType { @@ -309,7 +307,7 @@ func testEchoOneof2(t *testing.T, port int, apiPrefix string, contentType string } } -func testEchoBody(t *testing.T, port int, apiPrefix string) { +func testEchoBody(t *testing.T, port int, apiPrefix string, useTrailers bool) { sent := examplepb.UnannotatedSimpleMessage{Id: "example"} payload, err := marshaler.Marshal(&sent) if err != nil { @@ -317,9 +315,19 @@ func testEchoBody(t *testing.T, port int, apiPrefix string) { } apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo_body", port, apiPrefix) - resp, err := http.Post(apiURL, "", bytes.NewReader(payload)) + + req, err := http.NewRequest("POST", apiURL, bytes.NewReader(payload)) if err != nil { - t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) + t.Errorf("http.NewRequest() failed with %v; want success", err) + return + } + if useTrailers { + req.Header.Set("TE", "trailers") + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Errorf("client.Do(%v) failed with %v; want success", req, err) return } defer resp.Body.Close() @@ -329,45 +337,39 @@ func testEchoBody(t *testing.T, port int, apiPrefix string) { return } - if apiPrefix != "v1" { - if got, want := resp.StatusCode, http.StatusNotFound; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } - } else { - if got, want := resp.StatusCode, http.StatusOK; got != want { - t.Errorf("resp.StatusCode = %d; want %d", got, want) - t.Logf("%s", buf) - } + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Errorf("resp.StatusCode = %d; want %d", got, want) + t.Logf("%s", buf) + } - var received examplepb.UnannotatedSimpleMessage - if err := marshaler.Unmarshal(buf, &received); err != nil { - t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) - return - } - if diff := cmp.Diff(&received, &sent, protocmp.Transform()); diff != "" { - t.Errorf(diff) - } + var received examplepb.UnannotatedSimpleMessage + if err := marshaler.Unmarshal(buf, &received); err != nil { + t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) + return + } + if diff := cmp.Diff(&received, &sent, protocmp.Transform()); diff != "" { + t.Errorf(diff) + } - if value := resp.Header.Get("Content-Type"); value != "application/json" { - t.Errorf("Content-Type was %s, wanted %s", value, "application/json") - } + if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { + t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) + } + if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { + t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) + } - // fmt.Printf("headers: %v \n", resp.Header) - // fmt.Printf("apiURL: %s \n", apiURL) - // if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { - // t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) - // } - // if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { - // t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) - // } - - // if got, want := resp.Trailer.Get("Grpc-Trailer-Foo"), "foo2"; got != want { - // t.Errorf("Grpc-Trailer-Foo was %q, wanted %q", got, want) - // } - // if got, want := resp.Trailer.Get("Grpc-Trailer-Bar"), "bar2"; got != want { - // t.Errorf("Grpc-Trailer-Bar was %q, wanted %q", got, want) - // } + wantedTrailers := map[bool]map[string]string{ + true: { + "Grpc-Trailer-Foo": "foo2", + "Grpc-Trailer-Bar": "bar2", + }, + false: {}, + } + + for trailer, want := range wantedTrailers[useTrailers] { + if got := resp.Trailer.Get(trailer); got != want { + t.Errorf("%s was %q, wanted %q", trailer, got, want) + } } } diff --git a/examples/internal/proto/examplepb/BUILD.bazel b/examples/internal/proto/examplepb/BUILD.bazel index 16e18c5..8084e43 100644 --- a/examples/internal/proto/examplepb/BUILD.bazel +++ b/examples/internal/proto/examplepb/BUILD.bazel @@ -1,7 +1,7 @@ load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@com_github_binchencoder_ease_gateway//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") +load("//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") package(default_visibility = ["//visibility:public"]) @@ -34,6 +34,13 @@ package(default_visibility = ["//visibility:public"]) # gazelle:exclude openapi_merge_b.proto # gazelle:go_grpc_compilers //:go_apiv2, //:go_grpc, //protoc-gen-grpc-gateway:go_gen_grpc_gateway +genrule( + name = "generated_proto", + srcs = ["generated_input.proto"], + outs = ["generated_output.proto"], + cmd = "cp $< $@", # A simple copy simulates a generated proto file. +) + proto_library( name = "examplepb_proto", srcs = [ @@ -41,8 +48,8 @@ proto_library( # "unannotated_echo_service.proto", ], deps = [ - "//gateway/protoc-gen-openapiv2/options:options_proto", "//httpoptions:options_proto", + "//gateway/protoc-gen-openapiv2/options:options_proto", "@com_github_binchencoder_gateway_proto//data:data_proto", "@com_github_binchencoder_gateway_proto//frontend:error_proto", "@com_google_protobuf//:duration_proto", @@ -83,9 +90,7 @@ go_proto_library( deps = [ "//httpoptions", "@com_github_binchencoder_letsgo//grpc:go_default_library", - "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", - "@com_github_binchencoder_skylb_api//client/option:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", "//gateway/protoc-gen-openapiv2/options", "@com_github_golang_protobuf//descriptor:go_default_library_gen", # keep @@ -94,7 +99,6 @@ go_proto_library( "@go_googleapis//google/api:visibility_go_proto", "@go_googleapis//google/rpc:status_go_proto", "@org_golang_google_protobuf//proto:go_default_library", # keep - # "@org_golang_google_grpc//naming:go_default_library", ], ) @@ -107,7 +111,6 @@ go_library( "//gateway/runtime", "@com_github_grpc_ecosystem_grpc_gateway//utilities", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", - "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", "@org_golang_google_grpc//:go_default_library", "@org_golang_google_grpc//codes", diff --git a/examples/internal/proto/examplepb/echo_service.pb.go b/examples/internal/proto/examplepb/echo_service.pb.go new file mode 100755 index 0000000..c31ddf4 --- /dev/null +++ b/examples/internal/proto/examplepb/echo_service.pb.go @@ -0,0 +1,753 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.4 +// source: examples/internal/proto/examplepb/echo_service.proto + +package examplepb + +import ( + _ "github.com/binchencoder/ease-gateway/httpoptions" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" + structpb "google.golang.org/protobuf/types/known/structpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Embedded struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Mark: + // *Embedded_Progress + // *Embedded_Note + Mark isEmbedded_Mark `protobuf_oneof:"mark"` +} + +func (x *Embedded) Reset() { + *x = Embedded{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Embedded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Embedded) ProtoMessage() {} + +func (x *Embedded) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0] + 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 Embedded.ProtoReflect.Descriptor instead. +func (*Embedded) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{0} +} + +func (m *Embedded) GetMark() isEmbedded_Mark { + if m != nil { + return m.Mark + } + return nil +} + +func (x *Embedded) GetProgress() int64 { + if x, ok := x.GetMark().(*Embedded_Progress); ok { + return x.Progress + } + return 0 +} + +func (x *Embedded) GetNote() string { + if x, ok := x.GetMark().(*Embedded_Note); ok { + return x.Note + } + return "" +} + +type isEmbedded_Mark interface { + isEmbedded_Mark() +} + +type Embedded_Progress struct { + Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` +} + +type Embedded_Note struct { + Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` +} + +func (*Embedded_Progress) isEmbedded_Mark() {} + +func (*Embedded_Note) isEmbedded_Mark() {} + +type SimpleMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` + // Types that are assignable to Code: + // *SimpleMessage_LineNum + // *SimpleMessage_Lang + Code isSimpleMessage_Code `protobuf_oneof:"code"` + Status *Embedded `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` + // Types that are assignable to Ext: + // *SimpleMessage_En + // *SimpleMessage_No + Ext isSimpleMessage_Ext `protobuf_oneof:"ext"` +} + +func (x *SimpleMessage) Reset() { + *x = SimpleMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SimpleMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SimpleMessage) ProtoMessage() {} + +func (x *SimpleMessage) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1] + 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 SimpleMessage.ProtoReflect.Descriptor instead. +func (*SimpleMessage) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{1} +} + +func (x *SimpleMessage) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SimpleMessage) GetNum() int64 { + if x != nil { + return x.Num + } + return 0 +} + +func (m *SimpleMessage) GetCode() isSimpleMessage_Code { + if m != nil { + return m.Code + } + return nil +} + +func (x *SimpleMessage) GetLineNum() int64 { + if x, ok := x.GetCode().(*SimpleMessage_LineNum); ok { + return x.LineNum + } + return 0 +} + +func (x *SimpleMessage) GetLang() string { + if x, ok := x.GetCode().(*SimpleMessage_Lang); ok { + return x.Lang + } + return "" +} + +func (x *SimpleMessage) GetStatus() *Embedded { + if x != nil { + return x.Status + } + return nil +} + +func (m *SimpleMessage) GetExt() isSimpleMessage_Ext { + if m != nil { + return m.Ext + } + return nil +} + +func (x *SimpleMessage) GetEn() int64 { + if x, ok := x.GetExt().(*SimpleMessage_En); ok { + return x.En + } + return 0 +} + +func (x *SimpleMessage) GetNo() *Embedded { + if x, ok := x.GetExt().(*SimpleMessage_No); ok { + return x.No + } + return nil +} + +type isSimpleMessage_Code interface { + isSimpleMessage_Code() +} + +type SimpleMessage_LineNum struct { + LineNum int64 `protobuf:"varint,3,opt,name=line_num,json=lineNum,proto3,oneof"` +} + +type SimpleMessage_Lang struct { + Lang string `protobuf:"bytes,4,opt,name=lang,proto3,oneof"` +} + +func (*SimpleMessage_LineNum) isSimpleMessage_Code() {} + +func (*SimpleMessage_Lang) isSimpleMessage_Code() {} + +type isSimpleMessage_Ext interface { + isSimpleMessage_Ext() +} + +type SimpleMessage_En struct { + En int64 `protobuf:"varint,6,opt,name=en,proto3,oneof"` +} + +type SimpleMessage_No struct { + No *Embedded `protobuf:"bytes,7,opt,name=no,proto3,oneof"` +} + +func (*SimpleMessage_En) isSimpleMessage_Ext() {} + +func (*SimpleMessage_No) isSimpleMessage_Ext() {} + +type ValidationRuleTestRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` +} + +func (x *ValidationRuleTestRequest) Reset() { + *x = ValidationRuleTestRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidationRuleTestRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidationRuleTestRequest) ProtoMessage() {} + +func (x *ValidationRuleTestRequest) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2] + 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 ValidationRuleTestRequest.ProtoReflect.Descriptor instead. +func (*ValidationRuleTestRequest) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{2} +} + +func (x *ValidationRuleTestRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ValidationRuleTestRequest) GetNum() int64 { + if x != nil { + return x.Num + } + return 0 +} + +type ValidationRuleTestResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ValidationRuleTestResponse) Reset() { + *x = ValidationRuleTestResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidationRuleTestResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidationRuleTestResponse) ProtoMessage() {} + +func (x *ValidationRuleTestResponse) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3] + 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 ValidationRuleTestResponse.ProtoReflect.Descriptor instead. +func (*ValidationRuleTestResponse) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{3} +} + +type DynamicMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StructField *structpb.Struct `protobuf:"bytes,1,opt,name=struct_field,json=structField,proto3" json:"struct_field,omitempty"` + ValueField *structpb.Value `protobuf:"bytes,2,opt,name=value_field,json=valueField,proto3" json:"value_field,omitempty"` +} + +func (x *DynamicMessage) Reset() { + *x = DynamicMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DynamicMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DynamicMessage) ProtoMessage() {} + +func (x *DynamicMessage) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4] + 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 DynamicMessage.ProtoReflect.Descriptor instead. +func (*DynamicMessage) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{4} +} + +func (x *DynamicMessage) GetStructField() *structpb.Struct { + if x != nil { + return x.StructField + } + return nil +} + +func (x *DynamicMessage) GetValueField() *structpb.Value { + if x != nil { + return x.ValueField + } + return nil +} + +type DynamicMessageUpdate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Body *DynamicMessage `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` +} + +func (x *DynamicMessageUpdate) Reset() { + *x = DynamicMessageUpdate{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DynamicMessageUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DynamicMessageUpdate) ProtoMessage() {} + +func (x *DynamicMessageUpdate) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_echo_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 DynamicMessageUpdate.ProtoReflect.Descriptor instead. +func (*DynamicMessageUpdate) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP(), []int{5} +} + +func (x *DynamicMessageUpdate) GetBody() *DynamicMessage { + if x != nil { + return x.Body + } + return nil +} + +func (x *DynamicMessageUpdate) GetUpdateMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +var File_examples_internal_proto_examplepb_echo_service_proto protoreflect.FileDescriptor + +var file_examples_internal_proto_examplepb_echo_service_proto_rawDesc = []byte{ + 0x0a, 0x34, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x70, 0x62, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 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, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, + 0x6b, 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, 0x46, 0x0a, 0x08, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, + 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xa3, 0x02, + 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6e, 0x75, + 0x6d, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, + 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, + 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x50, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x4a, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, + 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, + 0x65, 0x78, 0x74, 0x22, 0x6f, 0x0a, 0x19, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x31, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xb2, 0xe4, + 0x34, 0x1d, 0x0a, 0x04, 0x08, 0x05, 0x10, 0x02, 0x0a, 0x09, 0x08, 0x06, 0x10, 0x02, 0x1a, 0x01, + 0x32, 0x20, 0x01, 0x0a, 0x0a, 0x08, 0x07, 0x10, 0x02, 0x1a, 0x02, 0x36, 0x31, 0x20, 0x01, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x42, 0x0d, 0xb2, 0xe4, 0x34, 0x09, 0x0a, 0x07, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x01, 0x30, 0x52, + 0x03, 0x6e, 0x75, 0x6d, 0x22, 0x1c, 0x0a, 0x1a, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x0e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, + 0x64, 0x12, 0x37, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x22, 0xa7, 0x01, 0x0a, 0x14, 0x44, + 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x12, 0x52, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x4d, 0x61, 0x73, 0x6b, 0x32, 0xd5, 0x08, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0xba, 0x02, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x3d, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, + 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, + 0x34, 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, + 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, + 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, + 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, + 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, + 0x31, 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, + 0x63, 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, + 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, + 0x65, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, + 0x7d, 0x12, 0xa8, 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x3d, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, + 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1e, 0xca, 0xf3, + 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, + 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0xa9, 0x01, 0x0a, + 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x3d, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3d, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x6d, 0x70, + 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0xca, 0xf3, 0x34, 0x19, 0x2a, + 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, + 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0xbb, 0x01, 0x0a, 0x09, 0x45, 0x63, 0x68, + 0x6f, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12, 0x44, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x44, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x44, 0x79, + 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x22, 0x22, 0xca, 0xf3, 0x34, 0x1e, 0x32, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, + 0x3a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0xd6, 0x01, 0x0a, 0x12, 0x45, 0x63, 0x68, 0x6f, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x49, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x4a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0xca, 0xf3, 0x34, 0x25, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x3a, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x1a, + 0x1b, 0xea, 0xf3, 0x34, 0x17, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, + 0x63, 0x1a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x52, 0x5a, 0x50, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_examples_internal_proto_examplepb_echo_service_proto_rawDescOnce sync.Once + file_examples_internal_proto_examplepb_echo_service_proto_rawDescData = file_examples_internal_proto_examplepb_echo_service_proto_rawDesc +) + +func file_examples_internal_proto_examplepb_echo_service_proto_rawDescGZIP() []byte { + file_examples_internal_proto_examplepb_echo_service_proto_rawDescOnce.Do(func() { + file_examples_internal_proto_examplepb_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_internal_proto_examplepb_echo_service_proto_rawDescData) + }) + return file_examples_internal_proto_examplepb_echo_service_proto_rawDescData +} + +var file_examples_internal_proto_examplepb_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_examples_internal_proto_examplepb_echo_service_proto_goTypes = []interface{}{ + (*Embedded)(nil), // 0: grpc.gateway.examples.internal.proto.examplepb.Embedded + (*SimpleMessage)(nil), // 1: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + (*ValidationRuleTestRequest)(nil), // 2: grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestRequest + (*ValidationRuleTestResponse)(nil), // 3: grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestResponse + (*DynamicMessage)(nil), // 4: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage + (*DynamicMessageUpdate)(nil), // 5: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate + (*structpb.Struct)(nil), // 6: google.protobuf.Struct + (*structpb.Value)(nil), // 7: google.protobuf.Value + (*fieldmaskpb.FieldMask)(nil), // 8: google.protobuf.FieldMask +} +var file_examples_internal_proto_examplepb_echo_service_proto_depIdxs = []int32{ + 0, // 0: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.Embedded + 0, // 1: grpc.gateway.examples.internal.proto.examplepb.SimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.Embedded + 6, // 2: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage.struct_field:type_name -> google.protobuf.Struct + 7, // 3: grpc.gateway.examples.internal.proto.examplepb.DynamicMessage.value_field:type_name -> google.protobuf.Value + 4, // 4: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate.body:type_name -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessage + 8, // 5: grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate.update_mask:type_name -> google.protobuf.FieldMask + 1, // 6: grpc.gateway.examples.internal.proto.examplepb.EchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 7: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 8: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 5, // 9: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoPatch:input_type -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate + 2, // 10: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoValidationRule:input_type -> grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestRequest + 1, // 11: grpc.gateway.examples.internal.proto.examplepb.EchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 12: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 1, // 13: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.SimpleMessage + 5, // 14: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoPatch:output_type -> grpc.gateway.examples.internal.proto.examplepb.DynamicMessageUpdate + 3, // 15: grpc.gateway.examples.internal.proto.examplepb.EchoService.EchoValidationRule:output_type -> grpc.gateway.examples.internal.proto.examplepb.ValidationRuleTestResponse + 11, // [11:16] is the sub-list for method output_type + 6, // [6:11] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_examples_internal_proto_examplepb_echo_service_proto_init() } +func file_examples_internal_proto_examplepb_echo_service_proto_init() { + if File_examples_internal_proto_examplepb_echo_service_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Embedded); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SimpleMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidationRuleTestRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidationRuleTestResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DynamicMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DynamicMessageUpdate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*Embedded_Progress)(nil), + (*Embedded_Note)(nil), + } + file_examples_internal_proto_examplepb_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*SimpleMessage_LineNum)(nil), + (*SimpleMessage_Lang)(nil), + (*SimpleMessage_En)(nil), + (*SimpleMessage_No)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_examples_internal_proto_examplepb_echo_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_examples_internal_proto_examplepb_echo_service_proto_goTypes, + DependencyIndexes: file_examples_internal_proto_examplepb_echo_service_proto_depIdxs, + MessageInfos: file_examples_internal_proto_examplepb_echo_service_proto_msgTypes, + }.Build() + File_examples_internal_proto_examplepb_echo_service_proto = out.File + file_examples_internal_proto_examplepb_echo_service_proto_rawDesc = nil + file_examples_internal_proto_examplepb_echo_service_proto_goTypes = nil + file_examples_internal_proto_examplepb_echo_service_proto_depIdxs = nil +} diff --git a/proto/examples/echo_service.pb.gw.go b/examples/internal/proto/examplepb/echo_service.pb.gw.go similarity index 70% rename from proto/examples/echo_service.pb.gw.go rename to examples/internal/proto/examplepb/echo_service.pb.gw.go index a97a509..b4a4cc8 100755 --- a/proto/examples/echo_service.pb.gw.go +++ b/examples/internal/proto/examplepb/echo_service.pb.gw.go @@ -1,12 +1,12 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: proto/examples/internal/echo_service.proto +// source: examples/internal/proto/examplepb/echo_service.proto /* -Package examples is a reverse proxy. +Package examplepb is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ -package examples +package examplepb import ( "context" @@ -21,15 +21,13 @@ import ( vexpb "github.com/binchencoder/gateway-proto/data" fpb "github.com/binchencoder/gateway-proto/frontend" lgr "github.com/binchencoder/letsgo/grpc" - "github.com/binchencoder/skylb-api/balancer" "github.com/binchencoder/skylb-api/client" - "github.com/binchencoder/skylb-api/client/option" skypb "github.com/binchencoder/skylb-api/proto" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/naming" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" ) @@ -40,6 +38,7 @@ var _ io.Reader var _ status.Status var _ = runtime.String var _ = utilities.NewDoubleArray +var _ = metadata.Join // var _ = descriptor.ForMessage var _ sync.RWMutex @@ -50,18 +49,19 @@ var _ client.ServiceCli var _ vexpb.ServiceId var _ = http.MethodGet var _ regexp.Regexp -var _ = balancer.ConsistentHashing -var _ option.BalancerCreator -var _ naming.Resolver + +// var _ = balancer.ConsistentHashing +// var _ option.BalancerCreator +// var _ naming.Resolver var _ strings.Reader var _ = utf8.UTFMax // TODO (jiezmo): check if there is any rule before create this var. -var proto_examples_echo_service_error = lgr.ToGrpcError(codes.InvalidArgument, &fpb.Error{Code: fpb.ErrorCode_BADPARAM_ERROR, Params: []string{"Validation error"}}) +var examples_internal_proto_examplepb_echo_service_error = lgr.ToGrpcError(codes.InvalidArgument, &fpb.Error{Code: fpb.ErrorCode_BADPARAM_ERROR, Params: []string{"Validation error"}}) // Validation methods start -func Validate__grpc_gateway_proto_examples_SimpleMessage(v *SimpleMessage) error { +func Validate__grpc_gateway_examples_internal_proto_examplepb_ValidationRuleTestRequest(v *ValidationRuleTestRequest) error { if v == nil { return nil } @@ -76,11 +76,11 @@ func Validate__grpc_gateway_proto_examples_SimpleMessage(v *SimpleMessage) error // Err if utf8.RuneCountInString(strings.TrimSpace(vv2)) <= 2 { - return proto_examples_echo_service_error + return examples_internal_proto_examplepb_echo_service_error } if utf8.RuneCountInString(strings.TrimSpace(vv2)) >= 61 { - return proto_examples_echo_service_error + return examples_internal_proto_examplepb_echo_service_error } } @@ -91,21 +91,11 @@ func Validate__grpc_gateway_proto_examples_SimpleMessage(v *SimpleMessage) error // Validation Field: Num if vv2 <= 0 { - return proto_examples_echo_service_error + return examples_internal_proto_examplepb_echo_service_error } } - // Validation Field: GetLineNum() - - // Validation Field: GetLang() - - // Validation Field: Status - - // Validation Field: GetEn() - - // Validation Field: GetNo() - return nil } @@ -147,13 +137,6 @@ func request_EchoService_Echo_0(ctx context.Context, marshaler runtime.Marshaler // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -245,13 +228,6 @@ func request_EchoService_Echo_1(ctx context.Context, marshaler runtime.Marshaler // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -369,13 +345,6 @@ func request_EchoService_Echo_2(ctx context.Context, marshaler runtime.Marshaler // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -508,13 +477,6 @@ func request_EchoService_Echo_3(ctx context.Context, marshaler runtime.Marshaler // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -620,13 +582,6 @@ func request_EchoService_Echo_4(ctx context.Context, marshaler runtime.Marshaler // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "Echo", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "Echo", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.Echo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -687,13 +642,6 @@ func request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marsh // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoBody", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "EchoBody", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.EchoBody(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -740,13 +688,6 @@ func request_EchoService_EchoDelete_0(ctx context.Context, marshaler runtime.Mar // Only hook up for non-stream call for now. - // Validate - // SimpleMessage - if err := Validate__grpc_gateway_proto_examples_SimpleMessage(&protoReq); err != nil { - runtime.RequestHandled(ctx, spec, "EchoService", "EchoDelete", nil, &metadata, err) - return nil, metadata, err - } - runtime.RequestParsed(ctx, spec, "EchoService", "EchoDelete", &protoReq, &metadata) ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) msg, err := client.EchoDelete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -774,22 +715,153 @@ func local_request_EchoService_EchoDelete_0(ctx context.Context, marshaler runti } +var ( + filter_EchoService_EchoPatch_0 = &utilities.DoubleArray{Encoding: map[string]int{"body": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DynamicMessageUpdate + var metadata runtime.ServerMetadata + spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + + 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.Body); err != nil && err != io.EOF { + runtime.RequestHandled(ctx, spec, "EchoService", "EchoPatch", nil, &metadata, err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Body); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoPatch_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + // Only hook up for non-stream call for now. + + runtime.RequestParsed(ctx, spec, "EchoService", "EchoPatch", &protoReq, &metadata) + ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) + msg, err := client.EchoPatch(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "EchoPatch", err) + // } + runtime.RequestHandled(ctx, spec, "EchoService", "EchoPatch", msg, &metadata, err) + return msg, metadata, err + +} + +func local_request_EchoService_EchoPatch_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DynamicMessageUpdate + 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.Body); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Body); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_EchoService_EchoPatch_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.EchoPatch(ctx, &protoReq) + return msg, metadata, err + +} + +func request_EchoService_EchoValidationRule_0(ctx context.Context, marshaler runtime.Marshaler, client EchoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ValidationRuleTestRequest + var metadata runtime.ServerMetadata + spec := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec + + 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 { + runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", nil, &metadata, err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + // Only hook up for non-stream call for now. + + // Validate + // ValidationRuleTestRequest + if err := Validate__grpc_gateway_examples_internal_proto_examplepb_ValidationRuleTestRequest(&protoReq); err != nil { + runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", nil, &metadata, err) + return nil, metadata, err + } + + runtime.RequestParsed(ctx, spec, "EchoService", "EchoValidationRule", &protoReq, &metadata) + ctx = runtime.PreLoadBalance(ctx, "ROUND_ROBIN", "", &protoReq) + msg, err := client.EchoValidationRule(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + // if err != nil { + // grpclog.Errorf("client.%s returns error: %v", "EchoValidationRule", err) + // } + runtime.RequestHandled(ctx, spec, "EchoService", "EchoValidationRule", msg, &metadata, err) + return msg, metadata, err + +} + +func local_request_EchoService_EchoValidationRule_0(ctx context.Context, marshaler runtime.Marshaler, server EchoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ValidationRuleTestRequest + 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 { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.EchoValidationRule(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterEchoServiceHandlerServer registers the http handlers for service EchoService to "mux". // UnaryRPC :call EchoServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterEchoServiceHandlerFromEndpoint instead. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterEchoServiceHandlerFromEndpoint instead. func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server EchoServiceServer) error { mux.Handle("POST", pattern_EchoService_Echo_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_Echo_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_Echo_0(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -803,13 +875,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("GET", pattern_EchoService_Echo_1, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}/{num}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_Echo_1(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_Echo_1(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -823,13 +899,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("GET", pattern_EchoService_Echo_2, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}/{num}/{lang}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_Echo_2(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_Echo_2(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -843,13 +923,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("GET", pattern_EchoService_Echo_3, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo1/{id}/{line_num}/{status.note}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_Echo_3(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_Echo_3(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -863,13 +947,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("GET", pattern_EchoService_Echo_4, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo2/{no.note}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_Echo_4(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_Echo_4(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -883,13 +971,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("POST", pattern_EchoService_EchoBody_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoBody") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", runtime.WithHTTPPathPattern("/v1/example/echo_body")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_EchoBody_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_EchoBody_0(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -903,13 +995,17 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux mux.Handle("DELETE", pattern_EchoService_EchoDelete_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoDelete") + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", runtime.WithHTTPPathPattern("/v1/example/echo_delete")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_EchoService_EchoDelete_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_EchoService_EchoDelete_0(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -920,6 +1016,54 @@ func RegisterEchoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", runtime.WithHTTPPathPattern("/v1/example/echo_patch")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EchoService_EchoPatch_0(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoPatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", runtime.WithHTTPPathPattern("/v1/example/echo:validationRules")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EchoService_EchoValidationRule_0(ctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoValidationRule_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1005,12 +1149,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_Echo_0(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1042,12 +1188,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}/{num}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_1(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_Echo_1(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1079,12 +1227,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo/{id}/{num}/{lang}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_2(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_Echo_2(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1116,12 +1266,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo1/{id}/{line_num}/{status.note}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_3(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_Echo_3(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1153,12 +1305,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/Echo") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", runtime.WithHTTPPathPattern("/v1/example/echo2/{no.note}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_Echo_4(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_Echo_4(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1190,12 +1344,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoBody") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", runtime.WithHTTPPathPattern("/v1/example/echo_body")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_EchoBody_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_EchoBody_0(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1227,12 +1383,14 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } ctx, cancel := context.WithCancel(req.Context()) defer cancel() - rctx, err := runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.proto.examples.EchoService/EchoDelete") + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", runtime.WithHTTPPathPattern("/v1/example/echo_delete")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_EchoService_EchoDelete_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_EchoService_EchoDelete_0(ctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) @@ -1243,6 +1401,84 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) + runtime.AddMethod(spec, "EchoService", "EchoPatch", "/v1/example/echo_patch", "PATCH", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") + mux.Handle("PATCH", pattern_EchoService_EchoPatch_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + // TODO(mojz): review all locking/unlocking logic. + // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + if client == nil { + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) + return + } + + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoPatch", w, req) + if err != nil { + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", runtime.WithHTTPPathPattern("/v1/example/echo_patch")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EchoService_EchoPatch_0(ctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoPatch_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + runtime.AddMethod(spec, "EchoService", "EchoValidationRule", "/v1/example/echo:validationRules", "POST", true, false, false, "UNSPECIFIED", "EASE_GATEWAY", "EASE_AUTH_TOKEN", "") + mux.Handle("POST", pattern_EchoService_EchoValidationRule_0, vexpb.ServiceId_CUSTOM_EASE_GATEWAY_TEST, func(inctx context.Context, w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + // TODO(mojz): review all locking/unlocking logic. + // internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RLock() + // defer internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_lock.RUnlock() + client := internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_client + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + if client == nil { + err := status.Error(codes.Internal, "service disabled") + runtime.HTTPError(inctx, mux, outboundMarshaler, w, req, err) + return + } + + ctx, err := runtime.RequestAccepted(inctx, internal_EchoService_CUSTOM_EASE_GATEWAY_TEST_spec, "EchoService", "EchoValidationRule", w, req) + if err != nil { + grpclog.Errorf("runtime.RequestAccepted returns error: %v", err) + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + // var err error + ctx, err = runtime.AnnotateContext(ctx, mux, req, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", runtime.WithHTTPPathPattern("/v1/example/echo:validationRules")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EchoService_EchoValidationRule_0(ctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_EchoService_EchoValidationRule_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1273,7 +1509,6 @@ func Enable_CUSTOM_EASE_GATEWAY_TEST__default__grpc_ServiceGroup() { internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Resolve(spec) - internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.EnableResolveFullEps() internal_CUSTOM_EASE_GATEWAY_TEST__default__grpc_skycli.Start(func(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { sg := runtime.GetServiceGroup(spec) for _, svc := range sg.Services { @@ -1304,6 +1539,10 @@ var ( pattern_EchoService_EchoBody_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_body"}, "")) pattern_EchoService_EchoDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_delete"}, "")) + + pattern_EchoService_EchoPatch_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo_patch"}, "")) + + pattern_EchoService_EchoValidationRule_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo"}, "validationRules")) ) var ( @@ -1320,6 +1559,10 @@ var ( forward_EchoService_EchoBody_0 = runtime.ForwardResponseMessage forward_EchoService_EchoDelete_0 = runtime.ForwardResponseMessage + + forward_EchoService_EchoPatch_0 = runtime.ForwardResponseMessage + + forward_EchoService_EchoValidationRule_0 = runtime.ForwardResponseMessage ) var ( diff --git a/examples/internal/proto/examplepb/echo_service_grpc.pb.go b/examples/internal/proto/examplepb/echo_service_grpc.pb.go new file mode 100755 index 0000000..0284d01 --- /dev/null +++ b/examples/internal/proto/examplepb/echo_service_grpc.pb.go @@ -0,0 +1,239 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package examplepb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion7 + +// EchoServiceClient is the client API for EchoService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type EchoServiceClient interface { + Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) + EchoValidationRule(ctx context.Context, in *ValidationRuleTestRequest, opts ...grpc.CallOption) (*ValidationRuleTestResponse, error) +} + +type echoServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { + return &echoServiceClient{cc} +} + +func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) { + out := new(DynamicMessageUpdate) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *echoServiceClient) EchoValidationRule(ctx context.Context, in *ValidationRuleTestRequest, opts ...grpc.CallOption) (*ValidationRuleTestResponse, error) { + out := new(ValidationRuleTestResponse) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// EchoServiceServer is the server API for EchoService service. +// All implementations should embed UnimplementedEchoServiceServer +// for forward compatibility +type EchoServiceServer interface { + Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) + EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) + EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) + EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) + EchoValidationRule(context.Context, *ValidationRuleTestRequest) (*ValidationRuleTestResponse, error) +} + +// UnimplementedEchoServiceServer should be embedded to have forward compatible implementations. +type UnimplementedEchoServiceServer struct { +} + +func (UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") +} +func (UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") +} +func (UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") +} +func (UnimplementedEchoServiceServer) EchoPatch(context.Context, *DynamicMessageUpdate) (*DynamicMessageUpdate, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoPatch not implemented") +} +func (UnimplementedEchoServiceServer) EchoValidationRule(context.Context, *ValidationRuleTestRequest) (*ValidationRuleTestResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoValidationRule not implemented") +} + +// UnsafeEchoServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to EchoServiceServer will +// result in compilation errors. +type UnsafeEchoServiceServer interface { + mustEmbedUnimplementedEchoServiceServer() +} + +func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { + s.RegisterService(&_EchoService_serviceDesc, srv) +} + +func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).Echo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/Echo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoBody(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoBody", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoDelete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoDelete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoPatch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DynamicMessageUpdate) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoPatch(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoPatch", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoPatch(ctx, req.(*DynamicMessageUpdate)) + } + return interceptor(ctx, in, info, handler) +} + +func _EchoService_EchoValidationRule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ValidationRuleTestRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).EchoValidationRule(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.EchoService/EchoValidationRule", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).EchoValidationRule(ctx, req.(*ValidationRuleTestRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _EchoService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.gateway.examples.internal.proto.examplepb.EchoService", + HandlerType: (*EchoServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Echo", + Handler: _EchoService_Echo_Handler, + }, + { + MethodName: "EchoBody", + Handler: _EchoService_EchoBody_Handler, + }, + { + MethodName: "EchoDelete", + Handler: _EchoService_EchoDelete_Handler, + }, + { + MethodName: "EchoPatch", + Handler: _EchoService_EchoPatch_Handler, + }, + { + MethodName: "EchoValidationRule", + Handler: _EchoService_EchoValidationRule_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "examples/internal/proto/examplepb/echo_service.proto", +} diff --git a/examples/internal/proto/examplepb/generated_input.proto b/examples/internal/proto/examplepb/generated_input.proto new file mode 100644 index 0000000..b2ac0c6 --- /dev/null +++ b/examples/internal/proto/examplepb/generated_input.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; +option go_package = "github.com/binchencoder/ease-gateway/examples/internal/proto/examplepb"; +package grpc.gateway.examples.internal.proto.examplepb; + +import "google/api/annotations.proto"; +import "google/protobuf/empty.proto"; +import "examples/internal/proto/examplepb/echo_service.proto"; + +// This file is run through a genrule. + +// Defines some more operations to be added to EchoService +service GeneratedService { + rpc Create(SimpleMessage) returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/v1/example/a_bit_of_everything/generated_create" + body: "*" + }; + } + +} diff --git a/examples/internal/proto/examplepb/generated_input.swagger.json b/examples/internal/proto/examplepb/generated_input.swagger.json new file mode 100644 index 0000000..65bc223 --- /dev/null +++ b/examples/internal/proto/examplepb/generated_input.swagger.json @@ -0,0 +1,347 @@ +{ + "swagger": "2.0", + "info": { + "title": "examples/internal/proto/examplepb/generated_input.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "GeneratedService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/example/a_bit_of_everything/generated_create": { + "post": { + "operationId": "GeneratedService_Create", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "properties": {} + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/examplepbABitOfEverything" + } + } + ], + "tags": [ + "GeneratedService" + ] + } + } + }, + "definitions": { + "ABitOfEverythingNested": { + "type": "object", + "example": { + "ok": "TRUE" + }, + "properties": { + "name": { + "type": "string", + "description": "name is nested field." + }, + "amount": { + "type": "integer", + "format": "int64" + }, + "ok": { + "$ref": "#/definitions/NestedDeepEnum", + "description": "DeepEnum description." + } + }, + "description": "Nested is nested type." + }, + "MessagePathEnumNestedPathEnum": { + "type": "string", + "enum": [ + "GHI", + "JKL" + ], + "default": "GHI" + }, + "NestedDeepEnum": { + "type": "string", + "enum": [ + "FALSE", + "TRUE" + ], + "default": "FALSE", + "description": "DeepEnum is one or zero.\n\n - FALSE: FALSE is false.\n - TRUE: TRUE is true." + }, + "examplepbABitOfEverything": { + "type": "object", + "example": { + "int64_value": 12, + "double_value": 12.3 + }, + "properties": { + "singleNested": { + "$ref": "#/definitions/ABitOfEverythingNested" + }, + "uuid": { + "type": "string", + "minLength": 1, + "pattern": "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}" + }, + "nested": { + "type": "array", + "items": { + "$ref": "#/definitions/ABitOfEverythingNested" + } + }, + "floatValue": { + "type": "number", + "format": "float", + "default": "0.2", + "description": "Float value field", + "required": [ + "floatValue" + ] + }, + "doubleValue": { + "type": "number", + "format": "double" + }, + "int64Value": { + "type": "string", + "format": "int64" + }, + "uint64Value": { + "type": "string", + "format": "uint64" + }, + "int32Value": { + "type": "integer", + "format": "int32" + }, + "fixed64Value": { + "type": "string", + "format": "uint64" + }, + "fixed32Value": { + "type": "integer", + "format": "int64" + }, + "boolValue": { + "type": "boolean" + }, + "stringValue": { + "type": "string" + }, + "bytesValue": { + "type": "string", + "format": "byte" + }, + "uint32Value": { + "type": "integer", + "format": "int64" + }, + "enumValue": { + "$ref": "#/definitions/examplepbNumericEnum" + }, + "pathEnumValue": { + "$ref": "#/definitions/pathenumPathEnum" + }, + "nestedPathEnumValue": { + "$ref": "#/definitions/MessagePathEnumNestedPathEnum" + }, + "sfixed32Value": { + "type": "integer", + "format": "int32" + }, + "sfixed64Value": { + "type": "string", + "format": "int64" + }, + "sint32Value": { + "type": "integer", + "format": "int32" + }, + "sint64Value": { + "type": "string", + "format": "int64" + }, + "repeatedStringValue": { + "type": "array", + "items": { + "type": "string" + } + }, + "oneofEmpty": { + "properties": {} + }, + "oneofString": { + "type": "string" + }, + "mapValue": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/examplepbNumericEnum" + } + }, + "mappedStringValue": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "mappedNestedValue": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ABitOfEverythingNested" + } + }, + "nonConventionalNameValue": { + "type": "string" + }, + "timestampValue": { + "type": "string", + "format": "date-time" + }, + "repeatedEnumValue": { + "type": "array", + "items": { + "$ref": "#/definitions/examplepbNumericEnum" + }, + "title": "repeated enum value. it is comma-separated in query" + }, + "repeatedEnumAnnotation": { + "type": "array", + "items": { + "$ref": "#/definitions/examplepbNumericEnum" + }, + "description": "Repeated numeric enum description.", + "title": "Repeated numeric enum title" + }, + "enumValueAnnotation": { + "$ref": "#/definitions/examplepbNumericEnum", + "description": "Numeric enum description.", + "title": "Numeric enum title" + }, + "repeatedStringAnnotation": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Repeated string description.", + "title": "Repeated string title" + }, + "repeatedNestedAnnotation": { + "type": "array", + "items": { + "$ref": "#/definitions/ABitOfEverythingNested" + }, + "description": "Repeated nested object description.", + "title": "Repeated nested object title" + }, + "nestedAnnotation": { + "$ref": "#/definitions/ABitOfEverythingNested", + "description": "Nested object description.", + "title": "Nested object title" + }, + "int64OverrideType": { + "type": "integer", + "format": "int64" + }, + "requiredStringViaFieldBehaviorAnnotation": { + "type": "string", + "title": "mark a field as required in Open API definition", + "required": [ + "requiredStringViaFieldBehaviorAnnotation" + ] + }, + "outputOnlyStringViaFieldBehaviorAnnotation": { + "type": "string", + "title": "mark a field as readonly in Open API definition", + "readOnly": true + }, + "optionalStringValue": { + "type": "string" + } + }, + "description": "Intentionally complicated message type to cover many features of Protobuf.", + "title": "A bit of everything", + "externalDocs": { + "description": "Find out more about ABitOfEverything", + "url": "https://github.com/grpc-ecosystem/grpc-gateway" + }, + "required": [ + "uuid", + "int64Value", + "doubleValue", + "floatValue", + "requiredStringViaFieldBehaviorAnnotation" + ] + }, + "examplepbNumericEnum": { + "type": "string", + "enum": [ + "ZERO", + "ONE" + ], + "default": "ZERO", + "description": "NumericEnum is one or zero.\n\n - ZERO: ZERO means 0\n - ONE: ONE means 1" + }, + "pathenumPathEnum": { + "type": "string", + "enum": [ + "ABC", + "DEF" + ], + "default": "ABC" + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." + } + }, + "additionalProperties": {}, + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "description": "The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]." + }, + "message": { + "type": "string", + "description": "A developer-facing error message, which should be in English. Any\nuser-facing error message should be localized and sent in the\n[google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client." + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufAny" + }, + "description": "A list of messages that carry the error details. There is a common set of\nmessage types for APIs to use." + } + }, + "description": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). Each `Status` message contains\nthree pieces of data: error code, error message, and error details.\n\nYou can find out more about this error model and how to work with it in the\n[API Design Guide](https://cloud.google.com/apis/design/errors)." + } + } +} diff --git a/examples/internal/proto/examplepb/standalone_echo_service.buf.gen.yaml b/examples/internal/proto/examplepb/standalone_echo_service.buf.gen.yaml new file mode 100644 index 0000000..8673875 --- /dev/null +++ b/examples/internal/proto/examplepb/standalone_echo_service.buf.gen.yaml @@ -0,0 +1,8 @@ +version: v1 +plugins: + - name: grpc-gateway + out: . + opt: + - paths=source_relative + - standalone=true + - grpc_api_configuration=examples/internal/proto/examplepb/standalone_echo_service.yaml diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.yaml b/examples/internal/proto/examplepb/unannotated_echo_servic.yaml similarity index 100% rename from examples/internal/proto/examplepb/unannotated_echo_service.yaml rename to examples/internal/proto/examplepb/unannotated_echo_servic.yaml diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.buf.gen.yaml b/examples/internal/proto/examplepb/unannotated_echo_service.buf.gen.yaml new file mode 100644 index 0000000..6ec699a --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.buf.gen.yaml @@ -0,0 +1,12 @@ +version: v1 +plugins: + - name: grpc-gateway + out: . + opt: + - paths=source_relative + - grpc_api_configuration=examples/internal/proto/examplepb/unannotated_echo_service.yaml + - name: openapiv2 + out: . + opt: + - grpc_api_configuration=examples/internal/proto/examplepb/unannotated_echo_service.yaml + - openapi_configuration=examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go new file mode 100755 index 0000000..9ef8067 --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.pb.go @@ -0,0 +1,437 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.19.4 +// source: examples/internal/proto/examplepb/unannotated_echo_service.proto + +package examplepb + +import ( + _ "github.com/binchencoder/ease-gateway/httpoptions" + duration "github.com/golang/protobuf/ptypes/duration" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type UnannotatedEmbedded struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Mark: + // *UnannotatedEmbedded_Progress + // *UnannotatedEmbedded_Note + Mark isUnannotatedEmbedded_Mark `protobuf_oneof:"mark"` +} + +func (x *UnannotatedEmbedded) Reset() { + *x = UnannotatedEmbedded{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnannotatedEmbedded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnannotatedEmbedded) ProtoMessage() {} + +func (x *UnannotatedEmbedded) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0] + 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 UnannotatedEmbedded.ProtoReflect.Descriptor instead. +func (*UnannotatedEmbedded) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP(), []int{0} +} + +func (m *UnannotatedEmbedded) GetMark() isUnannotatedEmbedded_Mark { + if m != nil { + return m.Mark + } + return nil +} + +func (x *UnannotatedEmbedded) GetProgress() int64 { + if x, ok := x.GetMark().(*UnannotatedEmbedded_Progress); ok { + return x.Progress + } + return 0 +} + +func (x *UnannotatedEmbedded) GetNote() string { + if x, ok := x.GetMark().(*UnannotatedEmbedded_Note); ok { + return x.Note + } + return "" +} + +type isUnannotatedEmbedded_Mark interface { + isUnannotatedEmbedded_Mark() +} + +type UnannotatedEmbedded_Progress struct { + Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` +} + +type UnannotatedEmbedded_Note struct { + Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` +} + +func (*UnannotatedEmbedded_Progress) isUnannotatedEmbedded_Mark() {} + +func (*UnannotatedEmbedded_Note) isUnannotatedEmbedded_Mark() {} + +type UnannotatedSimpleMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` + Duration *duration.Duration `protobuf:"bytes,3,opt,name=duration,proto3" json:"duration,omitempty"` + // Types that are assignable to Code: + // *UnannotatedSimpleMessage_LineNum + // *UnannotatedSimpleMessage_Lang + Code isUnannotatedSimpleMessage_Code `protobuf_oneof:"code"` + Status *UnannotatedEmbedded `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` + // Types that are assignable to Ext: + // *UnannotatedSimpleMessage_En + // *UnannotatedSimpleMessage_No + Ext isUnannotatedSimpleMessage_Ext `protobuf_oneof:"ext"` +} + +func (x *UnannotatedSimpleMessage) Reset() { + *x = UnannotatedSimpleMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnannotatedSimpleMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnannotatedSimpleMessage) ProtoMessage() {} + +func (x *UnannotatedSimpleMessage) ProtoReflect() protoreflect.Message { + mi := &file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1] + 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 UnannotatedSimpleMessage.ProtoReflect.Descriptor instead. +func (*UnannotatedSimpleMessage) Descriptor() ([]byte, []int) { + return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP(), []int{1} +} + +func (x *UnannotatedSimpleMessage) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UnannotatedSimpleMessage) GetNum() int64 { + if x != nil { + return x.Num + } + return 0 +} + +func (x *UnannotatedSimpleMessage) GetDuration() *duration.Duration { + if x != nil { + return x.Duration + } + return nil +} + +func (m *UnannotatedSimpleMessage) GetCode() isUnannotatedSimpleMessage_Code { + if m != nil { + return m.Code + } + return nil +} + +func (x *UnannotatedSimpleMessage) GetLineNum() int64 { + if x, ok := x.GetCode().(*UnannotatedSimpleMessage_LineNum); ok { + return x.LineNum + } + return 0 +} + +func (x *UnannotatedSimpleMessage) GetLang() string { + if x, ok := x.GetCode().(*UnannotatedSimpleMessage_Lang); ok { + return x.Lang + } + return "" +} + +func (x *UnannotatedSimpleMessage) GetStatus() *UnannotatedEmbedded { + if x != nil { + return x.Status + } + return nil +} + +func (m *UnannotatedSimpleMessage) GetExt() isUnannotatedSimpleMessage_Ext { + if m != nil { + return m.Ext + } + return nil +} + +func (x *UnannotatedSimpleMessage) GetEn() int64 { + if x, ok := x.GetExt().(*UnannotatedSimpleMessage_En); ok { + return x.En + } + return 0 +} + +func (x *UnannotatedSimpleMessage) GetNo() *UnannotatedEmbedded { + if x, ok := x.GetExt().(*UnannotatedSimpleMessage_No); ok { + return x.No + } + return nil +} + +type isUnannotatedSimpleMessage_Code interface { + isUnannotatedSimpleMessage_Code() +} + +type UnannotatedSimpleMessage_LineNum struct { + LineNum int64 `protobuf:"varint,4,opt,name=line_num,json=lineNum,proto3,oneof"` +} + +type UnannotatedSimpleMessage_Lang struct { + Lang string `protobuf:"bytes,5,opt,name=lang,proto3,oneof"` +} + +func (*UnannotatedSimpleMessage_LineNum) isUnannotatedSimpleMessage_Code() {} + +func (*UnannotatedSimpleMessage_Lang) isUnannotatedSimpleMessage_Code() {} + +type isUnannotatedSimpleMessage_Ext interface { + isUnannotatedSimpleMessage_Ext() +} + +type UnannotatedSimpleMessage_En struct { + En int64 `protobuf:"varint,7,opt,name=en,proto3,oneof"` +} + +type UnannotatedSimpleMessage_No struct { + No *UnannotatedEmbedded `protobuf:"bytes,8,opt,name=no,proto3,oneof"` +} + +func (*UnannotatedSimpleMessage_En) isUnannotatedSimpleMessage_Ext() {} + +func (*UnannotatedSimpleMessage_No) isUnannotatedSimpleMessage_Ext() {} + +var File_examples_internal_proto_examplepb_unannotated_echo_service_proto protoreflect.FileDescriptor + +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc = []byte{ + 0x0a, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x70, 0x62, 0x2f, 0x75, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x5f, + 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 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, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x51, 0x0a, 0x13, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, + 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, + 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, + 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xfb, 0x02, 0x0a, 0x18, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, + 0x6e, 0x75, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, + 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, + 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x5b, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, + 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, + 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x55, 0x0a, 0x02, + 0x6e, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, + 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x61, 0x74, 0x65, 0x64, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, 0x52, + 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, + 0x78, 0x74, 0x32, 0x94, 0x04, 0x0a, 0x16, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, + 0x65, 0x64, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x9a, 0x01, + 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, + 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, + 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x9e, 0x01, 0x0a, 0x08, 0x45, + 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, + 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0xa0, 0x01, 0x0a, 0x0a, + 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x48, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x1a, 0x48, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2e, 0x55, 0x6e, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, + 0x64, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x19, + 0xea, 0xf3, 0x34, 0x15, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, + 0x1a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x42, 0x52, 0x5a, 0x50, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x70, 0x62, 0x3b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescOnce sync.Once + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData = file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc +) + +func file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescGZIP() []byte { + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescOnce.Do(func() { + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData) + }) + return file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDescData +} + +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes = []interface{}{ + (*UnannotatedEmbedded)(nil), // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded + (*UnannotatedSimpleMessage)(nil), // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + (*duration.Duration)(nil), // 2: google.protobuf.Duration +} +var file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs = []int32{ + 2, // 0: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.duration:type_name -> google.protobuf.Duration + 0, // 1: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.status:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded + 0, // 2: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.no:type_name -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedEmbedded + 1, // 3: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 4: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 5: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:input_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 6: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 7: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoBody:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 1, // 8: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.EchoDelete:output_type -> grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + 6, // [6:9] is the sub-list for method output_type + 3, // [3:6] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_examples_internal_proto_examplepb_unannotated_echo_service_proto_init() } +func file_examples_internal_proto_examplepb_unannotated_echo_service_proto_init() { + if File_examples_internal_proto_examplepb_unannotated_echo_service_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnannotatedEmbedded); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnannotatedSimpleMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*UnannotatedEmbedded_Progress)(nil), + (*UnannotatedEmbedded_Note)(nil), + } + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*UnannotatedSimpleMessage_LineNum)(nil), + (*UnannotatedSimpleMessage_Lang)(nil), + (*UnannotatedSimpleMessage_En)(nil), + (*UnannotatedSimpleMessage_No)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes, + DependencyIndexes: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs, + MessageInfos: file_examples_internal_proto_examplepb_unannotated_echo_service_proto_msgTypes, + }.Build() + File_examples_internal_proto_examplepb_unannotated_echo_service_proto = out.File + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_rawDesc = nil + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_goTypes = nil + file_examples_internal_proto_examplepb_unannotated_echo_service_proto_depIdxs = nil +} diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go b/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go new file mode 100755 index 0000000..b76fb60 --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.pb.gw.go @@ -0,0 +1,3 @@ +// +build ignore + +package ignore \ No newline at end of file diff --git a/examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml b/examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml new file mode 100644 index 0000000..6329dad --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml @@ -0,0 +1,112 @@ +openapiOptions: + file: + # the file name must be the same as one passed to protoc when generating generating .swagger.json + - file: "examples/internal/proto/examplepb/unannotated_echo_service.proto" + option: + info: + title: Unannotated Echo + contact: + name: gRPC-Gateway project + url: https://github.com/grpc-ecosystem/grpc-gateway + email: none@example.com + license: + name: BSD 3-Clause License + url: https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt + version: "1.0" + extensions: + x-something-something: yadda + schemes: + - HTTP + - HTTPS + - WSS + consumes: + - application/json + - application/x-foo-mime + produces: + - application/json + - application/x-foo-mime + responses: + "403": + description: Returned when the user does not have permission to access the resource. + "404": + description: Returned when the resource does not exist. + schema: + jsonSchema: + type: + - STRING + securityDefinitions: + security: + ApiKeyAuth: + type: TYPE_API_KEY + name: X-API-Key + in: IN_HEADER + extensions: + x-amazon-apigateway-authorizer: + authorizerResultTtlInSeconds: 60 + type: token + x-amazon-apigateway-authtype: oauth2 + BasicAuth: + type: TYPE_BASIC + security: + - securityRequirement: + ApiKeyAuth: {} + BasicAuth: {} + - securityRequirement: + ApiKeyAuth: {} + OAuth2: + scope: + - read + - write + externalDocs: + description: More about gRPC-Gateway + url: https://github.com/grpc-ecosystem/grpc-gateway + extensions: + x-grpc-gateway-baz-list: + - one + - true + x-grpc-gateway-foo: bar + service: + - service: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService + option: + description: "UnannotatedEchoService description -- which should not be used in place of the documentation comment!" + external_docs: + url: "https://github.com/grpc-ecosystem/grpc-gateway" + description: "Find out more about UnannotatedEchoService" + method: + - method: grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService.Echo + option: + description: "Description Echo" + summary: "Summary: Echo rpc" + external_docs: + url: "https://github.com/grpc-ecosystem/grpc-gateway" + description: "Find out more Echo" + responses: + "200": + examples: + "application/json": '{"value": "the input value"}' + "503": + description: Returned when the resource is temporarily unavailable. + extensions: + x-number: 100 + "404": + description: Returned when the resource does not exist. + schema: + jsonSchema: + type: [INTEGER] + message: + - message: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage + option: + json_schema: + title: "A bit of everything" + description: "A simple message with many types" + required: ["id"] + external_docs: + url: "https://github.com/grpc-ecosystem/grpc-gateway" + description: "Find out more about UnannotatedSimpleMessage" + example: '{"id": "myid"}' + field: + - field: grpc.gateway.examples.internal.proto.examplepb.UnannotatedSimpleMessage.num + option: + description: "Int value field" + default: "42" + required: ["num"] diff --git a/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go b/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go new file mode 100755 index 0000000..8e1bb7c --- /dev/null +++ b/examples/internal/proto/examplepb/unannotated_echo_service_grpc.pb.go @@ -0,0 +1,167 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package examplepb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion7 + +// UnannotatedEchoServiceClient is the client API for UnannotatedEchoService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type UnannotatedEchoServiceClient interface { + Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) + EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) + EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) +} + +type unannotatedEchoServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUnannotatedEchoServiceClient(cc grpc.ClientConnInterface) UnannotatedEchoServiceClient { + return &unannotatedEchoServiceClient{cc} +} + +func (c *unannotatedEchoServiceClient) Echo(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *unannotatedEchoServiceClient) EchoBody(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *unannotatedEchoServiceClient) EchoDelete(ctx context.Context, in *UnannotatedSimpleMessage, opts ...grpc.CallOption) (*UnannotatedSimpleMessage, error) { + out := new(UnannotatedSimpleMessage) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UnannotatedEchoServiceServer is the server API for UnannotatedEchoService service. +// All implementations should embed UnimplementedUnannotatedEchoServiceServer +// for forward compatibility +type UnannotatedEchoServiceServer interface { + Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) + EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) + EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) +} + +// UnimplementedUnannotatedEchoServiceServer should be embedded to have forward compatible implementations. +type UnimplementedUnannotatedEchoServiceServer struct { +} + +func (UnimplementedUnannotatedEchoServiceServer) Echo(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") +} +func (UnimplementedUnannotatedEchoServiceServer) EchoBody(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") +} +func (UnimplementedUnannotatedEchoServiceServer) EchoDelete(context.Context, *UnannotatedSimpleMessage) (*UnannotatedSimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") +} + +// UnsafeUnannotatedEchoServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to UnannotatedEchoServiceServer will +// result in compilation errors. +type UnsafeUnannotatedEchoServiceServer interface { + mustEmbedUnimplementedUnannotatedEchoServiceServer() +} + +func RegisterUnannotatedEchoServiceServer(s *grpc.Server, srv UnannotatedEchoServiceServer) { + s.RegisterService(&_UnannotatedEchoService_serviceDesc, srv) +} + +func _UnannotatedEchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).Echo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/Echo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).Echo(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _UnannotatedEchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoBody", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).EchoBody(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _UnannotatedEchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnannotatedSimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService/EchoDelete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UnannotatedEchoServiceServer).EchoDelete(ctx, req.(*UnannotatedSimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +var _UnannotatedEchoService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.gateway.examples.internal.proto.examplepb.UnannotatedEchoService", + HandlerType: (*UnannotatedEchoServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Echo", + Handler: _UnannotatedEchoService_Echo_Handler, + }, + { + MethodName: "EchoBody", + Handler: _UnannotatedEchoService_EchoBody_Handler, + }, + { + MethodName: "EchoDelete", + Handler: _UnannotatedEchoService_EchoDelete_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "examples/internal/proto/examplepb/unannotated_echo_service.proto", +} diff --git a/examples/internal/server/BUILD.bazel b/examples/internal/server/BUILD.bazel index 84aea9b..458a608 100644 --- a/examples/internal/server/BUILD.bazel +++ b/examples/internal/server/BUILD.bazel @@ -3,29 +3,35 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") package(default_visibility = ["//visibility:public"]) go_library( - name = "go_default_library", + name = "server", srcs = [ "echo.go", "main.go", ], importpath = "github.com/binchencoder/ease-gateway/examples/internal/server", deps = [ - "//examples/internal/proto/examplepb:go_default_library", - "//gateway/runtime:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_rogpeppe_fastuuid//:go_default_library", + "//examples/internal/proto/examplepb", + "//gateway/runtime", + "@com_github_golang_glog//:glog", + "@com_github_rogpeppe_fastuuid//:fastuuid", "@go_googleapis//google/api:httpbody_go_proto", "@go_googleapis//google/rpc:errdetails_go_proto", "@go_googleapis//google/rpc:status_go_proto", - "@io_bazel_rules_go//proto/wkt:duration_go_proto", - "@io_bazel_rules_go//proto/wkt:empty_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", - "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", + "@org_golang_google_grpc//codes", + "@org_golang_google_grpc//metadata", + "@org_golang_google_grpc//status", + "@org_golang_google_protobuf//proto", + "@org_golang_google_protobuf//reflect/protoreflect", + "@org_golang_google_protobuf//types/known/durationpb", + "@org_golang_google_protobuf//types/known/emptypb", + "@org_golang_google_protobuf//types/known/wrapperspb", ], ) + +alias( + name = "go_default_library", + actual = ":server", + visibility = ["//examples:__subpackages__"], +) diff --git a/examples/internal/server/echo.go b/examples/internal/server/echo.go index 9cce632..3721fbf 100644 --- a/examples/internal/server/echo.go +++ b/examples/internal/server/echo.go @@ -13,7 +13,7 @@ import ( type echoServer struct{} -func newEchoServer() examples.EchoServiceServer { +func NewEchoServer() examples.EchoServiceServer { return new(echoServer) } diff --git a/examples/internal/server/main.go b/examples/internal/server/main.go index 2971ae1..60729e1 100644 --- a/examples/internal/server/main.go +++ b/examples/internal/server/main.go @@ -25,7 +25,7 @@ func Run(ctx context.Context, network, address string) error { }() s := grpc.NewServer() - examples.RegisterEchoServiceServer(s, newEchoServer()) + examples.RegisterEchoServiceServer(s, NewEchoServer()) go func() { defer s.GracefulStop() @@ -38,7 +38,7 @@ func Run(ctx context.Context, network, address string) error { func RunInProcessGateway(ctx context.Context, addr string, opts ...runtime.ServeMuxOption) error { mux := runtime.NewServeMux(opts...) - examples.RegisterEchoServiceHandlerServer(ctx, mux, newEchoServer()) + examples.RegisterEchoServiceHandlerServer(ctx, mux, NewEchoServer()) s := &http.Server{ Addr: addr, Handler: mux, diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go index 42f26d3..ce62bb0 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/generator.go @@ -47,16 +47,15 @@ func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix st "github.com/binchencoder/gateway-proto/data": "vexpb", "github.com/binchencoder/gateway-proto/frontend": "fpb", "github.com/binchencoder/letsgo/grpc": "lgr", - "github.com/binchencoder/skylb-api/balancer": "", - "github.com/binchencoder/skylb-api/client": "", - "github.com/binchencoder/skylb-api/client/option": "", - "github.com/binchencoder/skylb-api/proto": "skypb", - "google.golang.org/grpc": "", - "google.golang.org/grpc/codes": "", - // "google.golang.org/grpc/naming": "", - "google.golang.org/grpc/grpclog": "", - "google.golang.org/grpc/metadata": "", - "google.golang.org/grpc/status": "", + // "github.com/binchencoder/skylb-api/balancer": "", + "github.com/binchencoder/skylb-api/client": "", + // "github.com/binchencoder/skylb-api/client/option": "", + "github.com/binchencoder/skylb-api/proto": "skypb", + "google.golang.org/grpc": "", + "google.golang.org/grpc/codes": "", + "google.golang.org/grpc/grpclog": "", + "google.golang.org/grpc/metadata": "", + "google.golang.org/grpc/status": "", } { pkg := descriptor.GoPackage{ Path: pkgpath, diff --git a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go index 5b039c0..4bd2bc5 100644 --- a/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go +++ b/gateway/protoc-gen-grpc-gateway/internal/gengateway/template.go @@ -173,6 +173,11 @@ func applyTemplate(p param, reg *descriptor.Registry) (string, error) { if err := headerTemplate.Execute(w, p); err != nil { return "", err } + + if err := validatorTemplate.Execute(w, p); err != nil { + return "", err + } + var targetServices []*descriptor.Service for _, msg := range p.Messages { @@ -270,9 +275,9 @@ var _ client.ServiceCli var _ vexpb.ServiceId var _ = http.MethodGet var _ regexp.Regexp -var _ = balancer.ConsistentHashing -var _ option.BalancerCreator -var _ naming.Resolver +// var _ = balancer.ConsistentHashing +// var _ option.BalancerCreator +// var _ naming.Resolver var _ strings.Reader var _ = utf8.UTFMax @@ -867,7 +872,7 @@ func init() { {{range $svc := .Services}} // Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint is same as Register{{$svc.GetName}}{{$.RegisterFuncSuffix}} but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. -func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint(ctx context.Context, mux *runtime.ServeMux) (err error) { +func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint(mux *runtime.ServeMux) (err error) { // conn, err := grpc.Dial(endpoint, opts...) // if err != nil { // return err @@ -887,8 +892,8 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}FromEndpoint(ctx context.Co // }() // }() - return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(ctx, mux, conn) - // return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(nil, mux, nil) + // return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(ctx, mux, conn) + return Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}(nil, mux, nil) } // Register{{$svc.GetName}}{{$.RegisterFuncSuffix}} registers the http handlers for service {{$svc.GetName}} to "mux". @@ -934,7 +939,7 @@ func Register{{$svc.GetName}}{{$.RegisterFuncSuffix}}Client(ctx context.Context, {{- end }} defer cancel() // inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error + // var err error {{- if $b.PathTmpl }} ctx, err = runtime.AnnotateContext(ctx, mux, req, "/{{$svc.File.GetPackage}}.{{$svc.GetName}}/{{$m.GetName}}", runtime.WithHTTPPathPattern("{{$b.PathTmpl.Template}}")) {{- else -}} @@ -1016,13 +1021,9 @@ func Enable_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_ServiceGro {{if eq $svc.Balancer.String "ROUND_ROBIN"}} internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_skycli.Resolve(spec) {{else if eq $svc.Balancer.String "CONSISTENT"}} - internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_skycli.Resolve(spec, - option.WithBalancerCreator(func(r naming.Resolver) grpc.Balancer { - return balancer.ConsistentHashing(r) - }), + internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_skycli.Resolve(spec), ) {{end}} - internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_skycli.EnableResolveFullEps() internal_{{$svc.ServiceId}}__{{$svc.Namespace}}__{{$svc.PortName}}_skycli.Start(func(spec *skypb.ServiceSpec, conn *grpc.ClientConn) { sg := runtime.GetServiceGroup(spec) for _, svc := range sg.Services { diff --git a/gateway/runtime/BUILD.bazel b/gateway/runtime/BUILD.bazel index 55a2770..dab62cc 100644 --- a/gateway/runtime/BUILD.bazel +++ b/gateway/runtime/BUILD.bazel @@ -56,11 +56,11 @@ go_test( ], embed = [":runtime"], deps = [ - "//examples/internal/proto/examplepb:go_default_library", + "//examples/internal/proto/examplepb", "//gateway/internal:go_default_library", - "//gateway/runtime/internal/examplepb:go_default_library", - "@com_github_grpc_ecosystem_grpc_gateway//utilities", - "//httpoptions:go_default_library", + "//gateway/runtime/internal/examplepb", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", + "//httpoptions", "@com_github_binchencoder_letsgo//hashring:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", "@com_github_google_go_cmp//cmp", diff --git a/gateway/runtime/mux_test.go b/gateway/runtime/mux_test.go index 96d0836..180b7b7 100644 --- a/gateway/runtime/mux_test.go +++ b/gateway/runtime/mux_test.go @@ -681,7 +681,7 @@ func TestWithHealthEndpointAt_consistentWithHealthz(t *testing.T) { w := httptest.NewRecorder() runtime.NewServeMux( - runtime.WithHealthEndpointAt(client, endpointPath), + runtime.WithHealthEndpointAt(client, endpointPath, 1 /* sid */), ).ServeHTTP(w, r) refW := httptest.NewRecorder() diff --git a/go.mod b/go.mod index 5b4d68e..567506a 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/binchencoder/gateway-proto v0.0.7 github.com/binchencoder/letsgo v0.0.3 - github.com/binchencoder/skylb-api v0.0.5 + github.com/binchencoder/skylb-api v0.2.0 github.com/antihax/optional v1.0.0 github.com/golang/glog v1.0.0 github.com/golang/protobuf v1.5.2 @@ -31,7 +31,4 @@ require ( replace ( github.com/coreos/bbolt v1.3.4 => go.etcd.io/bbolt v1.3.4 github.com/coreos/bbolt v1.3.5 => go.etcd.io/bbolt v1.3.5 - // google.golang.org/grpc v1.30.0 => google.golang.org/grpc v1.29.1 - // google.golang.org/grpc v1.33.1 => google.golang.org/grpc v1.29.1 - // google.golang.org/grpc => google.golang.org/grpc v1.29.1 ) diff --git a/go.sum b/go.sum index 97044f8..28d730c 100644 --- a/go.sum +++ b/go.sum @@ -65,12 +65,6 @@ github.com/binchencoder/gateway-proto v0.0.7 h1:+3d1QEBqDxFrTIVrSiao4saXNFNeK/vx github.com/binchencoder/gateway-proto v0.0.7/go.mod h1:DUtwTL1FDBeVIDIHxS8v2YajyWqe444jSvCxexR161A= github.com/binchencoder/letsgo v0.0.3 h1:hEDDOeGdX9R/JPYMdVo9N/9iQa5BeBLluTssrNYy/ng= github.com/binchencoder/letsgo v0.0.3/go.mod h1:WbqNFa5gFsogqe3gtycvPYswprKV7eGJIxScwQhAg44= -github.com/binchencoder/skylb-api v0.0.3 h1:NnlPmEjTgOjH+s9TK3rBEY4Kn9aEzZkuEBUV2aR8UTM= -github.com/binchencoder/skylb-api v0.0.3/go.mod h1:j/ATHuW3TU7M5+fWeTqrvOzmFQI7Z4AVerdP6JYOkUk= -github.com/binchencoder/skylb-api v0.0.4 h1:HFQk6U+IerXWuQD6bxtGR6Zf7Q2Ulj87CZAd9G0vcnc= -github.com/binchencoder/skylb-api v0.0.4/go.mod h1:HoLyR+KbCm7bI2sRp+AA1pj159KRutdVYow6w3tbOLs= -github.com/binchencoder/skylb-api v0.0.5 h1:BM11MtrX7DrUKacLTEqudd4hietFlXRNr8Nh6dLSOCk= -github.com/binchencoder/skylb-api v0.0.5/go.mod h1:fUK5XeSBmuARvLeg+pab1FplK4x2+Q9zsmg4U8KNDBQ= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -420,12 +414,9 @@ go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -446,11 +437,9 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -459,29 +448,19 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -493,20 +472,18 @@ 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-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201026091529-146b70c837a4 h1:awiuzyrRjJDb+OXi9ceHO3SDxVoN3JER57mhtqkdQBs= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 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= @@ -516,31 +493,18 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -553,39 +517,32 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -595,8 +552,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -604,8 +559,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114 h1:DnSr2mCsxyCE6ZgIkmcWUQY2R5cH/6wL7eIxEmQOMSE= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -623,11 +576,9 @@ golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -655,36 +606,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200624020401-64a14ca9d1ad/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200702021140-07506425bd67 h1:4BC1C1i30F3MZeiIO6y6IIo4DxrtOwITK87bQl3lhFA= google.golang.org/genproto v0.0.0-20200702021140-07506425bd67/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -693,31 +614,14 @@ google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 h1:bFFRpT+e8JJVY7lMMfvezL1ZIwqiwmPl2bsE2yx4HqM= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/grpc/examples v0.0.0-20200630190442-3de8449f8555 h1:B6/wMqTY7mM93BBu0wfiO67B9+bcv4oQQsdrcijjfzA= -google.golang.org/grpc/examples v0.0.0-20200630190442-3de8449f8555/go.mod h1:5j1uub0jRGhRiSghIlrThmBUgcgLXOVJQ/l1getT4uo= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/integrate/BUILD.bazel b/integrate/BUILD.bazel index 4e1bdfc..f1d2fab 100755 --- a/integrate/BUILD.bazel +++ b/integrate/BUILD.bazel @@ -10,8 +10,8 @@ go_library( ), importpath = "github.com/binchencoder/ease-gateway/integrate", deps = [ - "//httpoptions:go_default_library", - "//gateway/runtime:go_default_library", + "//httpoptions", + "//gateway/runtime", "//integrate/metrics:go_default_library", "//util:go_default_library", "@com_github_binchencoder_gateway_proto//data:go_default_library", diff --git a/proto/examples/BUILD.bazel b/proto/examplepb/BUILD.bazel similarity index 79% rename from proto/examples/BUILD.bazel rename to proto/examplepb/BUILD.bazel index 5816390..7248172 100644 --- a/proto/examples/BUILD.bazel +++ b/proto/examplepb/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("//gateway/protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") @@ -29,30 +30,28 @@ go_proto_library( "//:go_grpc", "//gateway/protoc-gen-grpc-gateway:go_gen_grpc_gateway", # keep ], - importpath = "github.com/binchencoder/ease-gateway/proto/examples", + importpath = "github.com/binchencoder/ease-gateway/proto/examplepb", proto = ":examplepb_proto", deps = [ - "//httpoptions:go_default_library", - "//gateway/runtime:go_default_library", + "//httpoptions", + "//gateway/runtime", + "//gateway/protoc-gen-openapiv2/options", "@com_github_binchencoder_letsgo//grpc:go_default_library", - "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", - "@com_github_binchencoder_skylb_api//client/option:go_default_library", "@com_github_binchencoder_skylb_api//proto:go_default_library", - "@org_golang_google_grpc//naming:go_default_library", ], ) go_library( - name = "go_default_library", + name = "examplepb", embed = [":examplepb_go_proto"], - importpath = "github.com/binchencoder/ease-gateway/proto/examples", + importpath = "github.com/binchencoder/ease-gateway/proto/examplepb", deps = [ - "//httpoptions:go_default_library", - "//gateway/runtime:go_default_library", + "//httpoptions", + "//gateway/runtime", + "@com_github_grpc_ecosystem_grpc_gateway//utilities", "@com_github_binchencoder_gateway_proto//data:go_default_library", "@com_github_binchencoder_gateway_proto//frontend:go_default_library", - "@com_github_binchencoder_skylb_api//balancer:go_default_library", "@com_github_binchencoder_skylb_api//client:go_default_library", ], ) @@ -61,4 +60,9 @@ protoc_gen_openapiv2( name = "examplepb_protoc_gen_openapiv2", proto = ":examplepb_proto", single_output = False, # Outputs a single swagger.json file. +) + +alias( + name = "go_default_library", + actual = ":examplepb", ) \ No newline at end of file diff --git a/proto/examples/echo_service.proto b/proto/examplepb/echo_service.proto similarity index 95% rename from proto/examples/echo_service.proto rename to proto/examplepb/echo_service.proto index 713c6a0..72707da 100644 --- a/proto/examples/echo_service.proto +++ b/proto/examplepb/echo_service.proto @@ -1,10 +1,10 @@ syntax = "proto3"; -option go_package = "github.com/binchencoder/ease-gateway/gateway/proto/examples"; +option go_package = "github.com/binchencoder/ease-gateway/gateway/proto/examplepb"; -package grpc.gateway.proto.examples; +package grpc.gateway.proto.examplepb; -option java_package = "com.binchencoder.easegw.examples"; +option java_package = "com.binchencoder.easegw.examplepb"; option java_outer_classname = "ExamplesProto"; // import "google/api/annotations.proto"; diff --git a/proto/examples/echo_service.swagger.json b/proto/examplepb/echo_service.swagger.json similarity index 100% rename from proto/examples/echo_service.swagger.json rename to proto/examplepb/echo_service.swagger.json diff --git a/proto/examples/pom.xml b/proto/examplepb/pom.xml similarity index 100% rename from proto/examples/pom.xml rename to proto/examplepb/pom.xml diff --git a/proto/examples/echo_service.pb.go b/proto/examples/echo_service.pb.go deleted file mode 100755 index bdda4c4..0000000 --- a/proto/examples/echo_service.pb.go +++ /dev/null @@ -1,425 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.22.0 -// protoc v3.8.0 -// source: proto/examples/internal/echo_service.proto - -package examples - -import ( - _ "github.com/binchencoder/ease-gateway/httpoptions" - proto "github.com/golang/protobuf/proto" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -type Embedded struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Mark: - // *Embedded_Progress - // *Embedded_Note - Mark isEmbedded_Mark `protobuf_oneof:"mark"` -} - -func (x *Embedded) Reset() { - *x = Embedded{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_examples_echo_service_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Embedded) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Embedded) ProtoMessage() {} - -func (x *Embedded) ProtoReflect() protoreflect.Message { - mi := &file_proto_examples_echo_service_proto_msgTypes[0] - 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 Embedded.ProtoReflect.Descriptor instead. -func (*Embedded) Descriptor() ([]byte, []int) { - return file_proto_examples_echo_service_proto_rawDescGZIP(), []int{0} -} - -func (m *Embedded) GetMark() isEmbedded_Mark { - if m != nil { - return m.Mark - } - return nil -} - -func (x *Embedded) GetProgress() int64 { - if x, ok := x.GetMark().(*Embedded_Progress); ok { - return x.Progress - } - return 0 -} - -func (x *Embedded) GetNote() string { - if x, ok := x.GetMark().(*Embedded_Note); ok { - return x.Note - } - return "" -} - -type isEmbedded_Mark interface { - isEmbedded_Mark() -} - -type Embedded_Progress struct { - Progress int64 `protobuf:"varint,1,opt,name=progress,proto3,oneof"` -} - -type Embedded_Note struct { - Note string `protobuf:"bytes,2,opt,name=note,proto3,oneof"` -} - -func (*Embedded_Progress) isEmbedded_Mark() {} - -func (*Embedded_Note) isEmbedded_Mark() {} - -type SimpleMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Num int64 `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"` - // Types that are assignable to Code: - // *SimpleMessage_LineNum - // *SimpleMessage_Lang - Code isSimpleMessage_Code `protobuf_oneof:"code"` - Status *Embedded `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - // Types that are assignable to Ext: - // *SimpleMessage_En - // *SimpleMessage_No - Ext isSimpleMessage_Ext `protobuf_oneof:"ext"` -} - -func (x *SimpleMessage) Reset() { - *x = SimpleMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_examples_echo_service_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SimpleMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SimpleMessage) ProtoMessage() {} - -func (x *SimpleMessage) ProtoReflect() protoreflect.Message { - mi := &file_proto_examples_echo_service_proto_msgTypes[1] - 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 SimpleMessage.ProtoReflect.Descriptor instead. -func (*SimpleMessage) Descriptor() ([]byte, []int) { - return file_proto_examples_echo_service_proto_rawDescGZIP(), []int{1} -} - -func (x *SimpleMessage) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *SimpleMessage) GetNum() int64 { - if x != nil { - return x.Num - } - return 0 -} - -func (m *SimpleMessage) GetCode() isSimpleMessage_Code { - if m != nil { - return m.Code - } - return nil -} - -func (x *SimpleMessage) GetLineNum() int64 { - if x, ok := x.GetCode().(*SimpleMessage_LineNum); ok { - return x.LineNum - } - return 0 -} - -func (x *SimpleMessage) GetLang() string { - if x, ok := x.GetCode().(*SimpleMessage_Lang); ok { - return x.Lang - } - return "" -} - -func (x *SimpleMessage) GetStatus() *Embedded { - if x != nil { - return x.Status - } - return nil -} - -func (m *SimpleMessage) GetExt() isSimpleMessage_Ext { - if m != nil { - return m.Ext - } - return nil -} - -func (x *SimpleMessage) GetEn() int64 { - if x, ok := x.GetExt().(*SimpleMessage_En); ok { - return x.En - } - return 0 -} - -func (x *SimpleMessage) GetNo() *Embedded { - if x, ok := x.GetExt().(*SimpleMessage_No); ok { - return x.No - } - return nil -} - -type isSimpleMessage_Code interface { - isSimpleMessage_Code() -} - -type SimpleMessage_LineNum struct { - LineNum int64 `protobuf:"varint,3,opt,name=line_num,json=lineNum,proto3,oneof"` -} - -type SimpleMessage_Lang struct { - Lang string `protobuf:"bytes,4,opt,name=lang,proto3,oneof"` -} - -func (*SimpleMessage_LineNum) isSimpleMessage_Code() {} - -func (*SimpleMessage_Lang) isSimpleMessage_Code() {} - -type isSimpleMessage_Ext interface { - isSimpleMessage_Ext() -} - -type SimpleMessage_En struct { - En int64 `protobuf:"varint,6,opt,name=en,proto3,oneof"` -} - -type SimpleMessage_No struct { - No *Embedded `protobuf:"bytes,7,opt,name=no,proto3,oneof"` -} - -func (*SimpleMessage_En) isSimpleMessage_Ext() {} - -func (*SimpleMessage_No) isSimpleMessage_Ext() {} - -var File_proto_examples_echo_service_proto protoreflect.FileDescriptor - -var file_proto_examples_echo_service_proto_rawDesc = []byte{ - 0x0a, 0x21, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x1a, 0x1d, 0x68, 0x74, 0x74, 0x70, 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, - 0x46, 0x0a, 0x08, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, - 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, - 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, - 0x06, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0xaf, 0x02, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, - 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xb2, 0xe4, 0x34, 0x1d, 0x0a, 0x04, 0x08, 0x05, 0x10, - 0x02, 0x0a, 0x09, 0x08, 0x06, 0x10, 0x02, 0x1a, 0x01, 0x32, 0x20, 0x01, 0x0a, 0x0a, 0x08, 0x07, - 0x10, 0x02, 0x1a, 0x02, 0x36, 0x31, 0x20, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x03, - 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0d, 0xb2, 0xe4, 0x34, 0x09, 0x0a, - 0x07, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x01, 0x30, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x1b, 0x0a, - 0x08, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, - 0x00, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, - 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, - 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x45, - 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, - 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, - 0x6e, 0x12, 0x37, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x45, 0x6d, 0x62, 0x65, - 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, 0x52, 0x02, 0x6e, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x6f, - 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, 0x78, 0x74, 0x32, 0xcc, 0x04, 0x0a, 0x0b, 0x45, 0x63, - 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x94, 0x02, 0x0a, 0x04, 0x45, 0x63, - 0x68, 0x6f, 0x12, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, - 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, - 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, - 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb3, 0x01, 0xca, 0xf3, 0x34, - 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, - 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, - 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, - 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, - 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, 0x31, - 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, - 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, - 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, 0x65, - 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, - 0x12, 0x82, 0x01, 0x0a, 0x08, 0x45, 0x63, 0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2a, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, - 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, - 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1e, 0xca, 0xf3, 0x34, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, - 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, - 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x83, 0x01, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x12, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x73, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x1a, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0xca, 0xf3, - 0x34, 0x19, 0x2a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, - 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x1a, 0x1b, 0xea, 0xf3, 0x34, - 0x17, 0x08, 0xb6, 0x95, 0xff, 0xff, 0x07, 0x12, 0x04, 0x67, 0x72, 0x70, 0x63, 0x1a, 0x07, 0x64, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x01, 0x42, 0x6e, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, - 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x65, 0x61, 0x73, - 0x65, 0x67, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x42, 0x0d, 0x45, 0x78, - 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x3b, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x63, 0x68, 0x65, 0x6e, 0x63, - 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_proto_examples_echo_service_proto_rawDescOnce sync.Once - file_proto_examples_echo_service_proto_rawDescData = file_proto_examples_echo_service_proto_rawDesc -) - -func file_proto_examples_echo_service_proto_rawDescGZIP() []byte { - file_proto_examples_echo_service_proto_rawDescOnce.Do(func() { - file_proto_examples_echo_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_examples_echo_service_proto_rawDescData) - }) - return file_proto_examples_echo_service_proto_rawDescData -} - -var file_proto_examples_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_proto_examples_echo_service_proto_goTypes = []interface{}{ - (*Embedded)(nil), // 0: grpc.gateway.proto.examples.Embedded - (*SimpleMessage)(nil), // 1: grpc.gateway.proto.examples.SimpleMessage -} -var file_proto_examples_echo_service_proto_depIdxs = []int32{ - 0, // 0: grpc.gateway.proto.examples.SimpleMessage.status:type_name -> grpc.gateway.proto.examples.Embedded - 0, // 1: grpc.gateway.proto.examples.SimpleMessage.no:type_name -> grpc.gateway.proto.examples.Embedded - 1, // 2: grpc.gateway.proto.examples.EchoService.Echo:input_type -> grpc.gateway.proto.examples.SimpleMessage - 1, // 3: grpc.gateway.proto.examples.EchoService.EchoBody:input_type -> grpc.gateway.proto.examples.SimpleMessage - 1, // 4: grpc.gateway.proto.examples.EchoService.EchoDelete:input_type -> grpc.gateway.proto.examples.SimpleMessage - 1, // 5: grpc.gateway.proto.examples.EchoService.Echo:output_type -> grpc.gateway.proto.examples.SimpleMessage - 1, // 6: grpc.gateway.proto.examples.EchoService.EchoBody:output_type -> grpc.gateway.proto.examples.SimpleMessage - 1, // 7: grpc.gateway.proto.examples.EchoService.EchoDelete:output_type -> grpc.gateway.proto.examples.SimpleMessage - 5, // [5:8] is the sub-list for method output_type - 2, // [2:5] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name -} - -func init() { file_proto_examples_echo_service_proto_init() } -func file_proto_examples_echo_service_proto_init() { - if File_proto_examples_echo_service_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_proto_examples_echo_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Embedded); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_examples_echo_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SimpleMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_proto_examples_echo_service_proto_msgTypes[0].OneofWrappers = []interface{}{ - (*Embedded_Progress)(nil), - (*Embedded_Note)(nil), - } - file_proto_examples_echo_service_proto_msgTypes[1].OneofWrappers = []interface{}{ - (*SimpleMessage_LineNum)(nil), - (*SimpleMessage_Lang)(nil), - (*SimpleMessage_En)(nil), - (*SimpleMessage_No)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_proto_examples_echo_service_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_proto_examples_echo_service_proto_goTypes, - DependencyIndexes: file_proto_examples_echo_service_proto_depIdxs, - MessageInfos: file_proto_examples_echo_service_proto_msgTypes, - }.Build() - File_proto_examples_echo_service_proto = out.File - file_proto_examples_echo_service_proto_rawDesc = nil - file_proto_examples_echo_service_proto_goTypes = nil - file_proto_examples_echo_service_proto_depIdxs = nil -} diff --git a/proto/examples/echo_service_grpc.pb.go b/proto/examples/echo_service_grpc.pb.go deleted file mode 100755 index 91e6993..0000000 --- a/proto/examples/echo_service_grpc.pb.go +++ /dev/null @@ -1,158 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. - -package examples - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 - -// EchoServiceClient is the client API for EchoService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type EchoServiceClient interface { - Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) - EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) -} - -type echoServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { - return &echoServiceClient{cc} -} - -func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.proto.examples.EchoService/Echo", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.proto.examples.EchoService/EchoBody", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { - out := new(SimpleMessage) - err := c.cc.Invoke(ctx, "/grpc.gateway.proto.examples.EchoService/EchoDelete", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// EchoServiceServer is the server API for EchoService service. -type EchoServiceServer interface { - Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) - EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) -} - -// UnimplementedEchoServiceServer can be embedded to have forward compatible implementations. -type UnimplementedEchoServiceServer struct { -} - -func (*UnimplementedEchoServiceServer) Echo(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") -} -func (*UnimplementedEchoServiceServer) EchoBody(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoBody not implemented") -} -func (*UnimplementedEchoServiceServer) EchoDelete(context.Context, *SimpleMessage) (*SimpleMessage, error) { - return nil, status.Errorf(codes.Unimplemented, "method EchoDelete not implemented") -} - -func RegisterEchoServiceServer(s *grpc.Server, srv EchoServiceServer) { - s.RegisterService(&_EchoService_serviceDesc, srv) -} - -func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).Echo(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.proto.examples.EchoService/Echo", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoBody(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.proto.examples.EchoService/EchoBody", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SimpleMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EchoServiceServer).EchoDelete(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/grpc.gateway.proto.examples.EchoService/EchoDelete", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage)) - } - return interceptor(ctx, in, info, handler) -} - -var _EchoService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "grpc.gateway.proto.examples.EchoService", - HandlerType: (*EchoServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Echo", - Handler: _EchoService_Echo_Handler, - }, - { - MethodName: "EchoBody", - Handler: _EchoService_EchoBody_Handler, - }, - { - MethodName: "EchoDelete", - Handler: _EchoService_EchoDelete_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "proto/examples/internal/echo_service.proto", -} diff --git a/repositories.bzl b/repositories.bzl index 2c22a00..7b65028 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -1,6 +1,12 @@ load("@bazel_gazelle//:deps.bzl", "go_repository") def go_repositories(): + go_repository( + name = "com_github_binchencoder_ease_gateway", + importpath = "github.com/binchencoder/ease-gateway", + sum = "h1:wYZv8TO4TGO2U8HjEO5Odf8OYWQjfrXS8ddfGZWQfHI=", + version = "v1.0.3", + ) go_repository( name = "com_github_binchencoder_letsgo", importpath = "github.com/binchencoder/letsgo", @@ -10,8 +16,8 @@ def go_repositories(): go_repository( name = "com_github_binchencoder_skylb_api", importpath = "github.com/binchencoder/skylb-api", - sum = "h1:neSwlmR8As4mQkT9ITFv5SLBZ5f45i+HwXzKPso8gn0=", - version = "v0.0.6", + sum = "h1:CUhectaG+rrLs9pnfS9lvg6LqLD8Il4GyRTlNXNmS8Q=", + version = "v0.3.1", ) go_repository( name = "com_github_binchencoder_gateway_proto", @@ -19,24 +25,23 @@ def go_repositories(): sum = "h1:ZvjzhU0CR93EdhqGtQj0Wkwd76D+KsvMuNEMAS1XVos=", version = "v0.0.8", ) - go_repository( - name = "com_github_grpc_ecosystem_grpc_gateway", - importpath = "github.com/grpc-ecosystem/grpc-gateway/v2", - sum = "h1:SLkFeyLhrg86Ny5Wme4MGGace7EHfgsb07uWX/QUGEQ=", - version = "v2.9.0", + name = "com_github_armon_circbuf", + importpath = "github.com/armon/circbuf", + sum = "h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA=", + version = "v0.0.0-20150827004946-bbbad097214e", ) go_repository( - name = "com_github_grpc_ecosystem_grpc_opentracing", - importpath = "github.com/grpc-ecosystem/grpc-opentracing", - sum = "h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=", - version = "v0.0.0-20180507213350-8e809c8a8645", + name = "com_github_armon_go_metrics", + importpath = "github.com/armon/go-metrics", + sum = "h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=", + version = "v0.0.0-20180917152333-f0300d1749da", ) go_repository( - name = "com_github_grpc_ecosystem_go_grpc_middleware", - importpath = "github.com/grpc-ecosystem/go-grpc-middleware", - sum = "h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg=", - version = "v1.2.0", + name = "com_github_armon_go_radix", + importpath = "github.com/armon/go-radix", + sum = "h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to=", + version = "v0.0.0-20180808171621-7fddfc383310", ) go_repository( name = "com_github_beorn7_perks", @@ -56,6 +61,13 @@ def go_repositories(): sum = "h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=", version = "v1.7.0", ) + go_repository( + name = "com_github_fsnotify_fsnotify", + importpath = "github.com/fsnotify/fsnotify", + sum = "h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=", + version = "v1.4.7", + ) + go_repository( name = "com_github_ghodss_yaml", importpath = "github.com/ghodss/yaml", @@ -68,17 +80,31 @@ def go_repositories(): sum = "h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=", version = "v1.0.0", ) + + go_repository( + name = "com_github_golang_groupcache", + importpath = "github.com/golang/groupcache", + sum = "h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=", + version = "v0.0.0-20200121045136-8c9f03a8e57e", + ) + go_repository( + name = "com_github_golang_mock", + importpath = "github.com/golang/mock", + sum = "h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=", + version = "v1.4.4", + ) go_repository( name = "com_github_golang_protobuf", importpath = "github.com/golang/protobuf", sum = "h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=", version = "v1.5.2", ) + go_repository( - name = "com_github_google_uuid", - importpath = "github.com/google/uuid", - sum = "h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=", - version = "v1.1.2", + name = "com_github_google_btree", + importpath = "github.com/google/btree", + sum = "h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=", + version = "v1.0.0", ) go_repository( name = "com_github_google_go_cmp", @@ -86,6 +112,7 @@ def go_repositories(): sum = "h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=", version = "v0.5.7", ) + go_repository( name = "com_github_klauspost_cpuid", importpath = "github.com/klauspost/cpuid", @@ -105,11 +132,36 @@ def go_repositories(): version = "v0.1.7", ) go_repository( - name = "com_github_pborman_uuid", - importpath = "github.com/pborman/uuid", - sum = "h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=", + name = "com_github_google_uuid", + importpath = "github.com/google/uuid", + sum = "h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=", + version = "v1.1.2", + ) + + go_repository( + name = "com_github_grpc_ecosystem_go_grpc_middleware", + importpath = "github.com/grpc-ecosystem/go-grpc-middleware", + sum = "h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=", + version = "v1.0.0", + ) + go_repository( + name = "com_github_grpc_ecosystem_go_grpc_prometheus", + importpath = "github.com/grpc-ecosystem/go-grpc-prometheus", + sum = "h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=", version = "v1.2.0", ) + go_repository( + name = "com_github_grpc_ecosystem_grpc_gateway", + importpath = "github.com/grpc-ecosystem/grpc-gateway/v2", + sum = "h1:SLkFeyLhrg86Ny5Wme4MGGace7EHfgsb07uWX/QUGEQ=", + version = "v2.9.0", + ) + go_repository( + name = "com_github_grpc_ecosystem_grpc_opentracing", + importpath = "github.com/grpc-ecosystem/grpc-opentracing", + sum = "h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=", + version = "v0.0.0-20180507213350-8e809c8a8645", + ) go_repository( name = "com_github_go_kit_kit", importpath = "github.com/go-kit/kit", @@ -122,12 +174,6 @@ def go_repositories(): sum = "h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=", version = "v0.9.1", ) - go_repository( - name = "com_github_vividcortex_gohistogram", - importpath = "github.com/VividCortex/gohistogram", - sum = "h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=", - version = "v1.0.0", - ) go_repository( name = "com_github_klauspost_compress", importpath = "github.com/klauspost/compress", @@ -146,11 +192,54 @@ def go_repositories(): sum = "h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=", version = "v1.0.1", ) + go_repository( - name = "com_github_stretchr_testify", - importpath = "github.com/stretchr/testify", - sum = "h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=", - version = "v1.7.0", + name = "com_github_pborman_uuid", + importpath = "github.com/pborman/uuid", + sum = "h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=", + version = "v1.2.0", + ) + go_repository( + name = "com_github_prometheus_client_golang", + importpath = "github.com/prometheus/client_golang", + sum = "h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=", + version = "v0.9.3", + ) + go_repository( + name = "com_github_prometheus_client_model", + importpath = "github.com/prometheus/client_model", + sum = "h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=", + version = "v0.0.0-20190812154241-14fe0d1b01d4", + ) + go_repository( + name = "com_github_prometheus_common", + importpath = "github.com/prometheus/common", + sum = "h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=", + version = "v0.4.0", + ) + go_repository( + name = "com_github_prometheus_procfs", + importpath = "github.com/prometheus/procfs", + sum = "h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=", + version = "v0.0.0-20190507164030-5867b95ac084", + ) + go_repository( + name = "com_github_prometheus_tsdb", + importpath = "github.com/prometheus/tsdb", + sum = "h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=", + version = "v0.7.1", + ) + go_repository( + name = "com_github_smartystreets_assertions", + importpath = "github.com/smartystreets/assertions", + sum = "h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=", + version = "v0.0.0-20180927180507-b2de0cb4f26d", + ) + go_repository( + name = "com_github_smartystreets_goconvey", + importpath = "github.com/smartystreets/goconvey", + sum = "h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=", + version = "v1.6.4", ) go_repository( name = "com_github_soheilhy_cmux", @@ -171,34 +260,28 @@ def go_repositories(): version = "v2.2.0+incompatible", ) go_repository( - name = "com_github_prometheus_client_golang", - importpath = "github.com/prometheus/client_golang", - sum = "h1:Y8E/JaaPbmFSW2V81Ab/d8yZFYQQGbni1b1jPcG9Y6A=", - version = "v0.9.4", - ) - go_repository( - name = "com_github_prometheus_client_model", - importpath = "github.com/prometheus/client_model", - sum = "h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=", - version = "v0.2.0", + name = "com_github_rogpeppe_fastuuid", + importpath = "github.com/rogpeppe/fastuuid", + sum = "h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=", + version = "v1.2.0", ) go_repository( - name = "com_github_prometheus_common", - importpath = "github.com/prometheus/common", - sum = "h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=", - version = "v0.10.0", + name = "com_github_stretchr_objx", + importpath = "github.com/stretchr/objx", + sum = "h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=", + version = "v0.1.0", ) go_repository( - name = "com_github_prometheus_procfs", - importpath = "github.com/prometheus/procfs", - sum = "h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=", - version = "v0.1.3", + name = "com_github_stretchr_testify", + importpath = "github.com/stretchr/testify", + sum = "h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=", + version = "v1.7.0", ) go_repository( - name = "com_github_rogpeppe_fastuuid", - importpath = "github.com/rogpeppe/fastuuid", - sum = "h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=", - version = "v1.2.0", + name = "com_github_vividcortex_gohistogram", + importpath = "github.com/VividCortex/gohistogram", + sum = "h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=", + version = "v1.0.0", ) go_repository( @@ -210,8 +293,8 @@ def go_repositories(): go_repository( name = "in_gopkg_yaml_v3", importpath = "gopkg.in/yaml.v3", - sum = "h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=", - version = "v3.0.0-20200615113413-eeeca48fe776", + sum = "h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=", + version = "v3.0.0-20200313102051-9f266ea9e77c", ) go_repository( name = "io_etcd_go_bbolt", @@ -229,8 +312,8 @@ def go_repositories(): go_repository( name = "org_golang_google_genproto", importpath = "google.golang.org/genproto", - sum = "h1:ErU+UA6wxadoU8nWrsy5MZUVBs75K17zUCsUCIfrXCE=", - version = "v0.0.0-20220314164441-57ef72a4c106", + sum = "h1:0m9wktIpOxGw+SSKmydXWB3Z3GTfcPP6+q75HCQa6HI=", + version = "v0.0.0-20220324131243-acbaeb5b85eb", ) go_repository( name = "org_golang_google_grpc", @@ -238,12 +321,7 @@ def go_repositories(): sum = "h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=", version = "v1.45.0", ) - # go_repository( - # name = "org_golang_google_grpc", - # importpath = "google.golang.org/grpc", - # sum = "h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=", - # version = "v1.29.1", - # ) + go_repository( name = "org_golang_google_grpc_cmd_protoc_gen_go_grpc", importpath = "google.golang.org/grpc/cmd/protoc-gen-go-grpc", @@ -253,14 +331,8 @@ def go_repositories(): go_repository( name = "org_golang_google_protobuf", importpath = "google.golang.org/protobuf", - sum = "h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=", - version = "v1.27.1", - ) - go_repository( - name = "org_uber_go_atomic", - importpath = "go.uber.org/atomic", - sum = "h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=", - version = "v1.7.0", + sum = "h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=", + version = "v1.28.0", ) go_repository( name = "org_golang_x_crypto", @@ -356,4 +428,28 @@ def go_repositories(): importpath = "golang.org/x/xerrors", sum = "h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=", version = "v0.0.0-20200804184101-5ec99f83aff1", + ) + go_repository( + name = "org_uber_go_atomic", + importpath = "go.uber.org/atomic", + sum = "h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=", + version = "v1.7.0", + ) + go_repository( + name = "org_uber_go_multierr", + importpath = "go.uber.org/multierr", + sum = "h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=", + version = "v1.6.0", + ) + go_repository( + name = "org_uber_go_tools", + importpath = "go.uber.org/tools", + sum = "h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=", + version = "v0.0.0-20190618225709-2cfd321de3ee", + ) + go_repository( + name = "org_uber_go_zap", + importpath = "go.uber.org/zap", + sum = "h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=", + version = "v1.16.0", ) \ No newline at end of file From d128c779803715527823cbffd1cb076077fa8902 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sun, 27 Mar 2022 16:14:39 +0800 Subject: [PATCH 3/5] Upgrade google.golang.org/protobuf to v1.28.0 --- go.mod | 2 +- go.sum | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 567506a..afdf64f 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 google.golang.org/grpc v1.45.0 - google.golang.org/protobuf v1.27.1 + google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 sigs.k8s.io/yaml v1.3.0 ) diff --git a/go.sum b/go.sum index 28d730c..43f6716 100644 --- a/go.sum +++ b/go.sum @@ -630,14 +630,13 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 59f7bffc30a09684d8be7c65bcf38af8ed031a94 Mon Sep 17 00:00:00 2001 From: chenbin1314 Date: Sun, 27 Mar 2022 16:32:30 +0800 Subject: [PATCH 4/5] Update go.mod --- go.mod | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index afdf64f..8788eaa 100644 --- a/go.mod +++ b/go.mod @@ -5,12 +5,12 @@ go 1.17 require ( github.com/binchencoder/gateway-proto v0.0.7 github.com/binchencoder/letsgo v0.0.3 - github.com/binchencoder/skylb-api v0.2.0 + github.com/binchencoder/skylb-api v0.3.1 github.com/antihax/optional v1.0.0 github.com/golang/glog v1.0.0 github.com/golang/protobuf v1.5.2 github.com/google/go-cmp v0.5.7 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.8.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.9.0 github.com/rogpeppe/fastuuid v1.2.0 golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 From 3a3fd5829dd1be9c48ca02bed23ce0bc23c4cb10 Mon Sep 17 00:00:00 2001 From: binchencoder <15811514091@163.com> Date: Thu, 7 Apr 2022 17:59:37 +0800 Subject: [PATCH 5/5] Update Ease-Gateway.drawio --- docs/images/Ease-Gateway.drawio | 2 +- docs/images/Ease-Gateway.png | Bin 117260 -> 130330 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/images/Ease-Gateway.drawio b/docs/images/Ease-Gateway.drawio index eb6fe35..1019253 100644 --- a/docs/images/Ease-Gateway.drawio +++ b/docs/images/Ease-Gateway.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/docs/images/Ease-Gateway.png b/docs/images/Ease-Gateway.png index 29674e2981c493388af6573d50a39486774a64a5..69d1ae2877d5eb84bb0d1a9e2aca5e7b4beb2555 100644 GIT binary patch literal 130330 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%0AYHy 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 b_g+v?x2~*?zO^12`1e5R;r&tt%aH#E8(#K; literal 117260 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 A@&Et;