diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 99b9c42..c783225 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -20,7 +20,7 @@ jobs:
- name: Init MySQL
run: |
- go run ./cmd/gateway/main.go init -e dev
+ go run ./cmd/begonia init -e dev
cat ~/.begonia/admin-app.json
- name: Type a temporary tag
diff --git a/Makefile b/Makefile
index a785872..2fef709 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,11 @@
OUTPUT_DIR=./bin
+GO_BIN_DIR := $(shell go env GOPATH)/bin
version=$(shell git describe --tags --abbrev=0)
commit=$(shell git rev-parse --short HEAD)
build_time=$(shell date '+%Y%m%d%H%M%S')
build:
- go build -ldflags -X=github.com/begonia-org/begonia.Version=$(version)\ -X=github.com/begonia-org/begonia.BuildTime=$(build_time)\ -X=github.com/begonia-org/begonia.Commit=$(commit) -o $(OUTPUT_DIR)/begonia cmd/gateway/main.go
-
-.DEFAULT_GOAL := build
+ go build -ldflags -X=github.com/begonia-org/begonia.Version=$(version)\ -X=github.com/begonia-org/begonia.BuildTime=$(build_time)\ -X=github.com/begonia-org/begonia.Commit=$(commit) -o $(OUTPUT_DIR)/begonia cmd/begonia/*.go
+install:
+ go install -ldflags -X=github.com/begonia-org/begonia.Version=$(version)\ -X=github.com/begonia-org/begonia.BuildTime=$(build_time)\ -X=github.com/begonia-org/begonia.Commit=$(commit) cmd/begonia/*.go
+all: build install
+.DEFAULT_GOAL := all
diff --git a/README.md b/README.md
index 9946f33..e7e8949 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,81 @@
-
-
Begonia
+
Begonia
+
+
+[![Go Report Card](https://goreportcard.com/badge/github.com/begonia-org/begonia)](https://goreportcard.com/report/github.com/begonia-org/begonia)
+[![codecov](https://codecov.io/github/begonia-org/begonia/graph/badge.svg?token=VGGAA5A87B)](https://codecov.io/github/begonia-org/begonia)
+
+
+
+
+
+[English](README.md) | [中文](README_ZH.md)
+
+
-A gateway service that reverse proxies HTTP requests to gRPC services.
+Begonia is an HTTP to gRPC reverse proxy server, which registers services defined by `gRPC-gateway` to the gateway based on the descriptor_set_out generated by protoc, thereby implementing reverse proxy functionality. The HTTP service follows the RESTful standard to handle HTTP requests and forwards RESTful requests to gRPC services.
-
-# About
+# Features
+- Compatible with all `gRPC-gateway` feature functionalities
+
+- Supports converting all HTTP request methods and parameter formats into gRPC requests and data formats
+
+- Supports converting gRPC's bi-directional streaming transport into websocket protocol for request handling
+
+- Supports converting server-side streaming transport into SSE (Server-Side-Event) protocol for request handling
+
+- Based on custom `application/begonia-client-stream` request type to forward gRPC client streaming requests
+
+- Supports requests with `application/x-www-form-urlencoded` and `multipart/form-data` parameter formats
+
+- Rich built-in middleware, such as APIKEY verification, AKSK verification, `go-playground/validator` parameter verification middleware
+
+# Getting Started
+
+### Installation
+```bash
+git clone https://github.com/begonia-org/begonia.git
+```
+
+```bash
+cd begonia && make install
+```
+
+### Define proto
+Refer to [example/example.proto](example/example.proto)
+
+### Generate Descriptor Set
+
+```shell
+protoc --descriptor_set_out=example.pb --include_imports --proto_path=./ example.proto
+```
+
+### Start the Gateway Service
+
+#### 1. Build the runtime environment
+
+```bash
+docker compose up -d
+```
+
+#### 2. Initialize the database
+
+```bash
+begonia init -e dev
+```
+
+#### 3. Start the service
+
+```bash
+begonia start -e dev
+```
-Begonia is an HTTP to gRPC reverse proxy server that registers service routes to the gateway based on descriptor_set_out generated by protoc, thus implementing reverse proxy functionality. The HTTP service adheres to RESTful standards to handle HTTP requests and forwards RESTful requests to gRPC services
+#### 4. Register the service
+```bash
+go run . endpoint add -n "example" -d /data/work/begonia-org/begonia/example/example.pb -p 127.0.0.1:1949 -p 127.0.0.1:2024
+```
+#### 5. Test request service
+```
+curl -vvv http://127.0.0.1:12138/api/v1/example/hello
+```
\ No newline at end of file
diff --git a/README_ZH.md b/README_ZH.md
new file mode 100644
index 0000000..d69b307
--- /dev/null
+++ b/README_ZH.md
@@ -0,0 +1,88 @@
+
+
Begonia
+
+
+[![Go Report Card](https://goreportcard.com/badge/github.com/begonia-org/begonia)](https://goreportcard.com/report/github.com/begonia-org/begonia)
+[![codecov](https://codecov.io/github/begonia-org/begonia/graph/badge.svg?token=VGGAA5A87B)](https://codecov.io/github/begonia-org/begonia)
+
+
+
+
+
+[English](README.md) | [中文](README_ZH.md)
+
+
+
+Begonia 是一个 HTTP 到 gRPC 的反向代理服务器,它基于 protoc 生成的 descriptor_set_out 注册由`gRPC-gateway`定义的服务路由到网关,从而实现反向代理功能。HTTP 服务遵循 RESTful 标准来处理 HTTP 请求,并将 RESTful 请求转发到 gRPC 服务。
+
+
+
+# 特性
+
+- 兼容所有的`gRPC-gateway`功能特性
+
+- 支持所有 HTTP 请求方式和参数格式转换为 gRPC 请求和数据格式
+
+- 支持将 gRPC 的双向流式传输转换为 websocket 协议进行请求处理
+
+- 支持将服务端流式传输转换为 SSE(Server-Side-Event)协议进行请求处理
+
+- 基于自定义的`application/begonia-client-stream` 请求类型转发 gRPC 的客户端流式请求
+
+- 支持`application/x-www-form-urlencoded`和`multipart/form-data`参数格式的请求
+
+- 丰富的内置中间件,例如 APIKEY 校验、AKSK 校验,`go-playground/validator`参数校验中间件
+
+# 开始
+
+### 安装
+
+```bash
+git clone https://github.com/begonia-org/begonia.git
+```
+
+```bash
+cd begonia && make install
+```
+
+### 定义 proto
+
+参考[example/example.proto](example/example.proto)
+
+### 生成 Descriptor Set
+
+```shell
+protoc --descriptor_set_out=example.pb --include_imports --proto_path=./ example.proto
+```
+
+### 启动网关服务
+
+#### 1、构建运行环境
+
+```bash
+docker compose up -d
+```
+
+#### 2、初始化数据库
+
+```bash
+begonia init -e dev
+```
+
+#### 3、启动服务
+
+```bash
+begonia start -e dev
+```
+
+#### 4、注册服务
+
+```bash
+go run . endpoint add -n "example" -d /data/work/begonia-org/begonia/example/example.pb -p 127.0.0.1:1949 -p 127.0.0.1:2024
+```
+
+#### 5、测试请求服务
+
+```
+curl -vvv http://127.0.0.1:12138/api/v1/example/hello
+```
diff --git a/cmd/begonia/endpoint.go b/cmd/begonia/endpoint.go
new file mode 100644
index 0000000..f314d15
--- /dev/null
+++ b/cmd/begonia/endpoint.go
@@ -0,0 +1,115 @@
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+
+ goloadbalancer "github.com/begonia-org/go-loadbalancer"
+ api "github.com/begonia-org/go-sdk/api/app/v1"
+ endpoint "github.com/begonia-org/go-sdk/api/endpoint/v1"
+ "github.com/begonia-org/go-sdk/client"
+)
+
+var accessKey string
+var secret string
+var addr string
+
+func readInitAPP() {
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ log.Fatalf(err.Error())
+ return
+ }
+ path := filepath.Join(homeDir, ".begonia")
+ path = filepath.Join(path, "admin-app.json")
+ file, err := os.Open(path)
+ if err != nil {
+ log.Fatalf(err.Error())
+ return
+
+ }
+ defer file.Close()
+
+ decoder := json.NewDecoder(file)
+ app := &api.Apps{}
+ err = decoder.Decode(app)
+ if err != nil {
+ log.Fatalf(err.Error())
+ return
+
+ }
+ accessKey = app.AccessKey
+ secret = app.Secret
+ path2 := filepath.Join(homeDir, ".begonia")
+ path2 = filepath.Join(path2, "gateway.json")
+ gwFile, err := os.Open(path2)
+ if err != nil {
+ log.Fatalf(err.Error())
+ return
+
+ }
+ defer gwFile.Close()
+ gwDecoder := json.NewDecoder(gwFile)
+ gw := &struct {
+ Addr string `json:"addr"`
+ }{}
+ err = gwDecoder.Decode(gw)
+ if err != nil {
+ log.Fatalf(fmt.Sprintf("read gateway file error:%s", err.Error()))
+ return
+
+ }
+ addr = gw.Addr
+
+}
+func RegisterEndpoint(name string, endpoints []string, pbFile string, opts ...client.EndpointOption) {
+ readInitAPP()
+ pb, err := os.ReadFile(pbFile)
+ if err != nil {
+ panic(err)
+
+ }
+ apiClient := client.NewEndpointAPI(addr, accessKey, secret)
+ meta := make([]*endpoint.EndpointMeta, 0)
+ for i, v := range endpoints {
+ meta = append(meta, &endpoint.EndpointMeta{
+ Addr: v,
+ Weight: int32(i),
+ })
+ }
+ endpoint := &endpoint.EndpointSrvConfig{
+ DescriptorSet: pb,
+ Name: name,
+ ServiceName: name,
+ Description: name,
+ Balance: string(goloadbalancer.RRBalanceType),
+ Endpoints: meta,
+ Tags: make([]string, 0),
+ }
+ for _, opt := range opts {
+ opt(endpoint)
+
+ }
+ rsp, err := apiClient.PostEndpointConfig(context.Background(), endpoint)
+ if err != nil {
+ log.Fatalf(err.Error())
+ panic(err.Error())
+ }
+ log.Printf("#####################Add Endpoint Success#####################")
+ log.Printf("#####################ID:%s####################################", rsp.Id)
+}
+func DeleteEndpoint(id string) {
+ readInitAPP()
+ apiClient := client.NewEndpointAPI(addr, accessKey, secret)
+ log.Printf("#####################Delete Endpoint:%s#####################", id)
+ _, err := apiClient.DeleteEndpointConfig(context.Background(), id)
+ if err != nil {
+ log.Printf("delete err %v ", err)
+ panic(err.Error())
+ }
+ log.Printf("#####################Delete Endpoint Success#####################")
+}
diff --git a/cmd/begonia/main.go b/cmd/begonia/main.go
new file mode 100644
index 0000000..ec3a7fb
--- /dev/null
+++ b/cmd/begonia/main.go
@@ -0,0 +1,139 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "strings"
+
+ "github.com/begonia-org/begonia"
+ "github.com/begonia-org/begonia/config"
+ "github.com/begonia-org/begonia/gateway"
+ "github.com/begonia-org/begonia/internal"
+ "github.com/begonia-org/go-sdk/client"
+ "github.com/spf13/cobra"
+)
+
+// var ProviderSet = wire.NewSet(NewMasterCmd)
+func addCommonCommand(cmd *cobra.Command) *cobra.Command {
+ cmd.Flags().StringP("env", "e", "dev", "Runtime Environment")
+ return cmd
+}
+func NewInitCmd() *cobra.Command {
+ var cmd = &cobra.Command{
+ Use: "init",
+ Short: "Init Database",
+ Run: func(cmd *cobra.Command, args []string) {
+ env, _ := cmd.Flags().GetString("env")
+ config := config.ReadConfig(env)
+ operator := internal.InitOperatorApp(config)
+ log.Printf("init database")
+ err := operator.Init()
+ if err != nil {
+ log.Fatalf("failed to init database: %v", err)
+ }
+ },
+ }
+ return cmd
+
+}
+func NewGatewayCmd() *cobra.Command {
+ var cmd = &cobra.Command{
+ Use: "start",
+ Short: "Start Gateway Server",
+
+ Run: func(cmd *cobra.Command, args []string) {
+ endpoint, _ := cmd.Flags().GetString("endpoint")
+ env, _ := cmd.Flags().GetString("env")
+ config := config.ReadConfig(env)
+ worker := internal.New(config, gateway.Log, endpoint)
+ hd, _ := os.UserHomeDir()
+ _ = os.WriteFile(hd+"/.begonia/gateway.json", []byte(fmt.Sprintf(`{"addr":"http://%s"}`, endpoint)), 0666)
+ worker.Start()
+
+ },
+ }
+ cmd.Flags().StringP("endpoint", "", "127.0.0.1:12138", "Endpoint Of Your Service")
+ // cmd.Flags().StringP("name", "", "begonia", "Name Of Your Gateway Server")
+
+ return cmd
+}
+func NewEndpointDelCmd() *cobra.Command {
+ var cmd = &cobra.Command{
+ Use: "del",
+ Short: "Delete Service From Gateway",
+
+ Run: func(cmd *cobra.Command, args []string) {
+ id, _ := cmd.Flags().GetString("id")
+
+ DeleteEndpoint(id)
+ },
+ }
+ cmd.Flags().StringP("id", "i", "", "ID Of Your Service")
+ _ = cmd.MarkFlagRequired("id")
+ return cmd
+
+}
+func NewEndpointAddCmd() *cobra.Command {
+ var cmd = &cobra.Command{
+ Use: "add",
+ Short: "Add Service To Gateway",
+
+ Run: func(cmd *cobra.Command, args []string) {
+ name, _ := cmd.Flags().GetString("name")
+ desc, _ := cmd.Flags().GetString("desc")
+ tags, _ := cmd.Flags().GetStringArray("tags")
+ balance, _ := cmd.Flags().GetString("balance")
+ endpoints, _ := cmd.Flags().GetStringArray("endpoint")
+
+ RegisterEndpoint(name, endpoints, desc, client.WithBalance(strings.ToUpper(balance)), client.WithTags(tags))
+ },
+ }
+ cmd.Flags().StringArrayP("endpoint", "p", []string{}, "Endpoint Of Your Service (example:127.0.0.1:1949)")
+ cmd.Flags().StringP("name", "n", "", "Service Name")
+ cmd.Flags().StringP("desc", "d", "", "Descriptions Set Of Your Service (example:./example/example.pb)")
+ cmd.Flags().StringArrayP("tags", "t", []string{}, "Tags Of Your Service")
+ cmd.Flags().StringP("balance", "b", "RR", "Balance Type Of Your Service (options: RR WRR LC WLC CH SED NQ)")
+ _ = cmd.MarkFlagRequired("name")
+ _ = cmd.MarkFlagRequired("endpoint")
+ _ = cmd.MarkFlagRequired("desc")
+ return cmd
+}
+func NewEndpointCmd() *cobra.Command {
+ var cmd = &cobra.Command{
+ Use: "endpoint",
+ Short: "Manage Service Of Gateway",
+ }
+ // cmd.Flags().StringP("addr", "a", "http://127.0.0.1:12138", "Address Of Begonia Gateway server")
+ // _ = cmd.MarkFlagRequired("addr")
+
+ cmd.AddCommand(NewEndpointAddCmd())
+ cmd.AddCommand(NewEndpointDelCmd())
+ return cmd
+}
+func NewBegoniaInfoCmd() *cobra.Command {
+ var cmd = &cobra.Command{
+ Use: "info",
+ Short: "Output version info",
+ Run: func(cmd *cobra.Command, args []string) {
+ fmt.Println("Begonia Version: ", begonia.Version)
+ fmt.Println("Build Time: ", begonia.BuildTime)
+ fmt.Println("Commit: ", begonia.Commit)
+ fmt.Println("Env: ", begonia.Env)
+ },
+ }
+ return cmd
+}
+
+func main() {
+ cmd := NewGatewayCmd()
+ cmd = addCommonCommand(cmd)
+ rootCmd := &cobra.Command{Use: "gateway", Short: "网关服务"}
+ rootCmd.AddCommand(cmd)
+ rootCmd.AddCommand(NewBegoniaInfoCmd())
+ rootCmd.AddCommand(addCommonCommand(NewInitCmd()))
+ rootCmd.AddCommand(NewEndpointCmd())
+ if err := cmd.Execute(); err != nil {
+ log.Fatalf("failed to start master: %v", err)
+ }
+}
diff --git a/cmd/gateway/main.go b/cmd/gateway/main.go
deleted file mode 100644
index 12374f7..0000000
--- a/cmd/gateway/main.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package main
-
-import (
- "log"
-
- "github.com/begonia-org/begonia/config"
- "github.com/begonia-org/begonia/gateway"
- "github.com/begonia-org/begonia/internal"
- "github.com/spf13/cobra"
-)
-
-// var ProviderSet = wire.NewSet(NewMasterCmd)
-func addCommonCommand(cmd *cobra.Command) *cobra.Command {
- cmd.Flags().StringP("env", "e", "dev", "Runtime Environment")
- return cmd
-}
-func NewInitCmd() *cobra.Command {
- var cmd = &cobra.Command{
- Use: "init",
- Short: "初始化数据库",
- Run: func(cmd *cobra.Command, args []string) {
- env, _ := cmd.Flags().GetString("env")
- config := config.ReadConfig(env)
- operator := internal.InitOperatorApp(config)
- log.Printf("init database")
- err := operator.Init()
- if err != nil {
- log.Fatalf("failed to init database: %v", err)
- }
- },
- }
- return cmd
-
-}
-func NewGatewayCmd() *cobra.Command {
- var cmd = &cobra.Command{
- Use: "start",
- Short: "启动网关服务",
-
- Run: func(cmd *cobra.Command, args []string) {
- endpoint, _ := cmd.Flags().GetString("endpoint")
- // name, _ := cmd.Flags().GetString("name")
- env, _ := cmd.Flags().GetString("env")
- config := config.ReadConfig(env)
- worker := internal.New(config, gateway.Log, endpoint)
- worker.Start()
-
- },
- }
- cmd.Flags().StringP("endpoint", "", "127.0.0.1:12138", "Endpoint Of Your Service")
- // cmd.Flags().StringP("name", "", "begonia", "Name Of Your Gateway Server")
-
- return cmd
-}
-
-func main() {
- cmd := NewGatewayCmd()
- cmd = addCommonCommand(cmd)
- rootCmd := &cobra.Command{Use: "gateway", Short: "网关服务"}
- rootCmd.AddCommand(cmd)
- rootCmd.AddCommand(addCommonCommand(NewInitCmd()))
-
- if err := cmd.Execute(); err != nil {
- log.Fatalf("failed to start master: %v", err)
- }
-}
diff --git a/config/settings.yml b/config/settings.yml
index 1abcc40..6dea531 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -69,23 +69,23 @@ gateway:
auth: 4
# only_api_key_auth: 4
rpc:
- - server:
- name: "example-server"
- endpoint:
- - addr: "127.0.0.1:21216"
- weight: 1
- - addr: "127.0.0.1:21217"
- weight: 2
- priority: 10
- timeout: 30
- lb: "round_robin"
- pool:
- max_open_conns: 100
- max_idle_conns: 50
- size: 50
- timeout: 10
- min_idle_conns: 25
- max_active_conns: 20
+ # - server:
+ # name: "example-server"
+ # endpoint:
+ # - addr: "127.0.0.1:21216"
+ # weight: 1
+ # - addr: "127.0.0.1:21217"
+ # weight: 2
+ # priority: 10
+ # timeout: 30
+ # lb: "round_robin"
+ # pool:
+ # max_open_conns: 100
+ # max_idle_conns: 50
+ # size: 50
+ # timeout: 10
+ # min_idle_conns: 25
+ # max_active_conns: 20
descriptor:
out_dir: "/tmp/begonia/descriptors"
test:
@@ -108,6 +108,37 @@ test:
rsa:
private_key: "/tmp/auth_private_key.pem"
public_key: "/tmp/auth_public_key.pem"
+ gateway:
+ cors:
+ - "localhost"
+ - "127.0.0.1:8081"
+ - "example.com"
+ plugins:
+ local:
+ logger: 1
+ exception: 0
+ http: 2
+ params_validator: 3
+ auth: 4
+ # only_api_key_auth: 4
+ rpc:
+ - server:
+ name: "example-server"
+ endpoint:
+ - addr: "127.0.0.1:21216"
+ weight: 1
+ - addr: "127.0.0.1:21217"
+ weight: 2
+ priority: 10
+ timeout: 30
+ lb: "round_robin"
+ pool:
+ max_open_conns: 100
+ max_idle_conns: 50
+ size: 50
+ timeout: 10
+ min_idle_conns: 25
+ max_active_conns: 20
common:
cache_prefix_key: "begonia"
filter_key_prefix: "filter"
diff --git a/example/example.pb b/example/example.pb
new file mode 100644
index 0000000..aa9e1b3
Binary files /dev/null and b/example/example.pb differ
diff --git a/example/example.proto b/example/example.proto
new file mode 100644
index 0000000..6533842
--- /dev/null
+++ b/example/example.proto
@@ -0,0 +1,101 @@
+syntax = "proto3";
+
+option go_package = "example";
+option java_multiple_files = true;
+option java_package = "io.grpc.examples.example";
+option java_outer_classname = "ExampleProto";
+option objc_class_prefix = "HLW";
+
+package helloworld;
+
+import "google/api/annotations.proto";
+import "google/protobuf/field_mask.proto";
+import "google/protobuf/descriptor.proto";
+import "google/api/httpbody.proto";
+
+// The greeting service definition.
+// The greeting service definition.
+service Greeter {
+ // Sends a greeting
+ rpc SayHello (HelloRequest) returns (HelloReply) {
+ option (google.api.http)={
+ post:"/api/v1/example/post"
+ body:"*"
+ };
+ }
+ rpc SayHelloGet (HelloRequest) returns (HelloReply) {
+ option (google.api.http)={
+ get:"/api/v1/example/{name}"
+ };
+ }
+
+ rpc SayHelloServerSideEvent (HelloRequest) returns (stream HelloReply) {
+ option (google.api.http) = {
+ get: "/api/v1/example/server/sse/{name}"
+ };
+ }
+
+ rpc SayHelloClientStream (stream HelloRequest) returns (RepeatedReply) {
+ option (google.api.http) = {
+ post: "/api/v1/example/client/stream"
+ body: "*"
+ };
+
+ }
+ rpc SayHelloWebsocket (stream HelloRequest) returns (stream HelloReply) {
+ option (google.api.http) = {
+ get: "/api/v1/example/server/websocket"
+ };
+ }
+ rpc SayHelloBody (google.api.HttpBody) returns (google.api.HttpBody) {
+ option (google.api.http) = {
+ post: "/api/v1/example/body"
+ };
+ }
+ rpc SayHelloError (ErrorRequest) returns (HelloReply) {
+ option (google.api.http) = {
+ get: "/api/v1/example/error/test"
+ };
+ }
+
+}
+
+message ErrorRequest {
+ string msg = 1;
+ int32 code = 2;
+}
+// The request message containing the user's name.
+message HelloRequest {
+ string msg = 1;
+ string name = 2;
+}
+message HelloSubRequest{
+ // @gotags: validate:"required"
+ string sub_msg = 1[json_name="sub_msg"];
+ // @gotags: validate:"required"
+ string sub_name = 2[json_name="sub_name"];
+ google.protobuf.FieldMask update_mask = 3[json_name="update_mask"];
+}
+message HelloRequestWithValidator{
+ // @gotags: validate:"required"
+ string msg = 1;
+ // @gotags: validate:"required"
+ string name = 2;
+ // @gotags: validate:"gte=18,lte=35"
+ int32 age = 3;
+ // @gotags: validate:"required"
+ HelloSubRequest sub = 4;
+ // @gotags: validate:"dive,required"
+ repeated HelloSubRequest subs = 5;
+ google.protobuf.FieldMask update_mask = 6[json_name="update_mask"];
+
+
+}
+// The response message containing the greetings
+message HelloReply {
+ string message = 1;
+ string name = 2;
+}
+message RepeatedReply{
+ repeated HelloReply replies = 1;
+}
diff --git a/example/google/api/annotations.proto b/example/google/api/annotations.proto
new file mode 100644
index 0000000..efdab3d
--- /dev/null
+++ b/example/google/api/annotations.proto
@@ -0,0 +1,31 @@
+// Copyright 2015 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.
+
+syntax = "proto3";
+
+package google.api;
+
+import "google/api/http.proto";
+import "google/protobuf/descriptor.proto";
+
+option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
+option java_multiple_files = true;
+option java_outer_classname = "AnnotationsProto";
+option java_package = "com.google.api";
+option objc_class_prefix = "GAPI";
+
+extend google.protobuf.MethodOptions {
+ // See `HttpRule`.
+ HttpRule http = 72295728;
+}
diff --git a/example/google/api/http.proto b/example/google/api/http.proto
new file mode 100644
index 0000000..31d867a
--- /dev/null
+++ b/example/google/api/http.proto
@@ -0,0 +1,379 @@
+// Copyright 2023 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.
+
+syntax = "proto3";
+
+package google.api;
+
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
+option java_multiple_files = true;
+option java_outer_classname = "HttpProto";
+option java_package = "com.google.api";
+option objc_class_prefix = "GAPI";
+
+// 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.
+message Http {
+ // A list of HTTP configuration rules that apply to individual API methods.
+ //
+ // **NOTE:** All service configuration rules follow "last one wins" order.
+ repeated HttpRule rules = 1;
+
+ // 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.
+ bool fully_decode_reserved_expansion = 2;
+}
+
+// # 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.
+message HttpRule {
+ // Selects a method to which this rule applies.
+ //
+ // Refer to [selector][google.api.DocumentationRule.selector] for syntax
+ // details.
+ string selector = 1;
+
+ // 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.
+ oneof pattern {
+ // Maps to HTTP GET. Used for listing and getting information about
+ // resources.
+ string get = 2;
+
+ // Maps to HTTP PUT. Used for replacing a resource.
+ string put = 3;
+
+ // Maps to HTTP POST. Used for creating a resource or performing an action.
+ string post = 4;
+
+ // Maps to HTTP DELETE. Used for deleting a resource.
+ string delete = 5;
+
+ // Maps to HTTP PATCH. Used for updating a resource.
+ string patch = 6;
+
+ // 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.
+ CustomHttpPattern custom = 8;
+ }
+
+ // 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.
+ string body = 7;
+
+ // 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.
+ string response_body = 12;
+
+ // 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).
+ repeated HttpRule additional_bindings = 11;
+}
+
+// A custom pattern is used for defining custom HTTP verb.
+message CustomHttpPattern {
+ // The name of this custom HTTP verb.
+ string kind = 1;
+
+ // The path matched by this custom verb.
+ string path = 2;
+}
diff --git a/example/google/api/httpbody.proto b/example/google/api/httpbody.proto
new file mode 100644
index 0000000..7f1685e
--- /dev/null
+++ b/example/google/api/httpbody.proto
@@ -0,0 +1,81 @@
+// Copyright 2023 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.
+
+syntax = "proto3";
+
+package google.api;
+
+import "google/protobuf/any.proto";
+
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody";
+option java_multiple_files = true;
+option java_outer_classname = "HttpBodyProto";
+option java_package = "com.google.api";
+option objc_class_prefix = "GAPI";
+
+// Message that represents an arbitrary HTTP body. It should only be used for
+// payload formats that can't be represented as JSON, such as raw binary or
+// an HTML page.
+//
+//
+// This message can be used both in streaming and non-streaming API methods in
+// the request as well as the response.
+//
+// It can be used as a top-level request field, which is convenient if one
+// wants to extract parameters from either the URL or HTTP template into the
+// request fields and also want access to the raw HTTP body.
+//
+// Example:
+//
+// message GetResourceRequest {
+// // A unique request id.
+// string request_id = 1;
+//
+// // The raw HTTP body is bound to this field.
+// google.api.HttpBody http_body = 2;
+//
+// }
+//
+// service ResourceService {
+// rpc GetResource(GetResourceRequest)
+// returns (google.api.HttpBody);
+// rpc UpdateResource(google.api.HttpBody)
+// returns (google.protobuf.Empty);
+//
+// }
+//
+// Example with streaming methods:
+//
+// service CaldavService {
+// rpc GetCalendar(stream google.api.HttpBody)
+// returns (stream google.api.HttpBody);
+// rpc UpdateCalendar(stream google.api.HttpBody)
+// returns (stream google.api.HttpBody);
+//
+// }
+//
+// Use of this type only changes how the request and response bodies are
+// handled, all other features will continue to work unchanged.
+message HttpBody {
+ // The HTTP Content-Type header value specifying the content type of the body.
+ string content_type = 1;
+
+ // The HTTP request/response body as raw binary.
+ bytes data = 2;
+
+ // Application specific response metadata. Must be set in the first response
+ // for streaming APIs.
+ repeated google.protobuf.Any extensions = 3;
+}
diff --git a/example/google/protobuf/any.proto b/example/google/protobuf/any.proto
new file mode 100755
index 0000000..561da0c
--- /dev/null
+++ b/example/google/protobuf/any.proto
@@ -0,0 +1,161 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option go_package = "google.golang.org/protobuf/types/known/anypb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "AnyProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+
+// `Any` contains an arbitrary serialized protocol buffer message along with a
+// URL that describes the type of the serialized message.
+//
+// Protobuf library provides support to pack/unpack Any values in the form
+// of utility functions or additional generated methods of the Any type.
+//
+// Example 1: Pack and unpack a message in C++.
+//
+// Foo foo = ...;
+// Any any;
+// any.PackFrom(foo);
+// ...
+// if (any.UnpackTo(&foo)) {
+// ...
+// }
+//
+// Example 2: Pack and unpack a message in Java.
+//
+// Foo foo = ...;
+// Any any = Any.pack(foo);
+// ...
+// if (any.is(Foo.class)) {
+// foo = any.unpack(Foo.class);
+// }
+// // or ...
+// if (any.isSameTypeAs(Foo.getDefaultInstance())) {
+// foo = any.unpack(Foo.getDefaultInstance());
+// }
+//
+// Example 3: Pack and unpack a message in Python.
+//
+// foo = Foo(...)
+// any = Any()
+// any.Pack(foo)
+// ...
+// if any.Is(Foo.DESCRIPTOR):
+// any.Unpack(foo)
+// ...
+//
+// Example 4: Pack and unpack a message in Go
+//
+// foo := &pb.Foo{...}
+// any, err := anypb.New(foo)
+// if err != nil {
+// ...
+// }
+// ...
+// foo := &pb.Foo{}
+// if err := any.UnmarshalTo(foo); err != nil {
+// ...
+// }
+//
+// The pack methods provided by protobuf library will by default use
+// 'type.googleapis.com/full.type.name' as the type URL and the unpack
+// methods only use the fully qualified type name after the last '/'
+// in the type URL, for example "foo.bar.com/x/y.z" will yield type
+// name "y.z".
+//
+// JSON
+//
+// The JSON representation of an `Any` value uses the regular
+// representation of the deserialized, embedded message, with an
+// additional field `@type` which contains the type URL. Example:
+//
+// package google.profile;
+// message Person {
+// string first_name = 1;
+// string last_name = 2;
+// }
+//
+// {
+// "@type": "type.googleapis.com/google.profile.Person",
+// "firstName": ,
+// "lastName":
+// }
+//
+// If the embedded message type is well-known and has a custom JSON
+// representation, that representation will be embedded adding a field
+// `value` which holds the custom JSON in addition to the `@type`
+// field. Example (for message [google.protobuf.Duration][]):
+//
+// {
+// "@type": "type.googleapis.com/google.protobuf.Duration",
+// "value": "1.212s"
+// }
+//
+message Any {
+ // A URL/resource name that uniquely identifies the type of the serialized
+ // protocol buffer message. This string must contain at least
+ // one "/" character. The last segment of the URL's path must represent
+ // the fully qualified name of the type (as in
+ // `path/google.protobuf.Duration`). The name should be in a canonical form
+ // (e.g., leading "." is not accepted).
+ //
+ // In practice, teams usually precompile into the binary all types that they
+ // expect it to use in the context of Any. However, for URLs which use the
+ // scheme `http`, `https`, or no scheme, one can optionally set up a type
+ // server that maps type URLs to message definitions as follows:
+ //
+ // * If no scheme is provided, `https` is assumed.
+ // * An HTTP GET on the URL must yield a [google.protobuf.Type][]
+ // value in binary format, or produce an error.
+ // * Applications are allowed to cache lookup results based on the
+ // URL, or have them precompiled into a binary to avoid any
+ // lookup. Therefore, binary compatibility needs to be preserved
+ // on changes to types. (Use versioned type names to manage
+ // breaking changes.)
+ //
+ // Note: this functionality is not currently available in the official
+ // protobuf release, and it is not used for type URLs beginning with
+ // type.googleapis.com.
+ //
+ // Schemes other than `http`, `https` (or the empty scheme) might be
+ // used with implementation specific semantics.
+ //
+ string type_url = 1;
+
+ // Must be a valid serialized protocol buffer of the above specified type.
+ bytes value = 2;
+}
diff --git a/example/google/protobuf/descriptor.proto b/example/google/protobuf/descriptor.proto
new file mode 100755
index 0000000..3b38675
--- /dev/null
+++ b/example/google/protobuf/descriptor.proto
@@ -0,0 +1,975 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+//
+// The messages in this file describe the definitions found in .proto files.
+// A valid .proto file can be translated directly to a FileDescriptorProto
+// without any other information (e.g. without reading its imports).
+
+syntax = "proto2";
+
+package google.protobuf;
+
+option go_package = "google.golang.org/protobuf/types/descriptorpb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DescriptorProtos";
+option csharp_namespace = "Google.Protobuf.Reflection";
+option objc_class_prefix = "GPB";
+option cc_enable_arenas = true;
+
+// descriptor.proto must be optimized for speed because reflection-based
+// algorithms don't work during bootstrapping.
+option optimize_for = SPEED;
+
+// The protocol compiler can output a FileDescriptorSet containing the .proto
+// files it parses.
+message FileDescriptorSet {
+ repeated FileDescriptorProto file = 1;
+}
+
+// Describes a complete .proto file.
+message FileDescriptorProto {
+ optional string name = 1; // file name, relative to root of source tree
+ optional string package = 2; // e.g. "foo", "foo.bar", etc.
+
+ // Names of files imported by this file.
+ repeated string dependency = 3;
+ // Indexes of the public imported files in the dependency list above.
+ repeated int32 public_dependency = 10;
+ // Indexes of the weak imported files in the dependency list.
+ // For Google-internal migration only. Do not use.
+ repeated int32 weak_dependency = 11;
+
+ // All top-level definitions in this file.
+ repeated DescriptorProto message_type = 4;
+ repeated EnumDescriptorProto enum_type = 5;
+ repeated ServiceDescriptorProto service = 6;
+ repeated FieldDescriptorProto extension = 7;
+
+ optional FileOptions options = 8;
+
+ // This field contains optional information about the original source code.
+ // You may safely remove this entire field without harming runtime
+ // functionality of the descriptors -- the information is needed only by
+ // development tools.
+ optional SourceCodeInfo source_code_info = 9;
+
+ // The syntax of the proto file.
+ // The supported values are "proto2", "proto3", and "editions".
+ //
+ // If `edition` is present, this value must be "editions".
+ optional string syntax = 12;
+
+ // The edition of the proto file, which is an opaque string.
+ optional string edition = 13;
+}
+
+// Describes a message type.
+message DescriptorProto {
+ optional string name = 1;
+
+ repeated FieldDescriptorProto field = 2;
+ repeated FieldDescriptorProto extension = 6;
+
+ repeated DescriptorProto nested_type = 3;
+ repeated EnumDescriptorProto enum_type = 4;
+
+ message ExtensionRange {
+ optional int32 start = 1; // Inclusive.
+ optional int32 end = 2; // Exclusive.
+
+ optional ExtensionRangeOptions options = 3;
+ }
+ repeated ExtensionRange extension_range = 5;
+
+ repeated OneofDescriptorProto oneof_decl = 8;
+
+ optional MessageOptions options = 7;
+
+ // Range of reserved tag numbers. Reserved tag numbers may not be used by
+ // fields or extension ranges in the same message. Reserved ranges may
+ // not overlap.
+ message ReservedRange {
+ optional int32 start = 1; // Inclusive.
+ optional int32 end = 2; // Exclusive.
+ }
+ repeated ReservedRange reserved_range = 9;
+ // Reserved field names, which may not be used by fields in the same message.
+ // A given name may only be reserved once.
+ repeated string reserved_name = 10;
+}
+
+message ExtensionRangeOptions {
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+// Describes a field within a message.
+message FieldDescriptorProto {
+ enum Type {
+ // 0 is reserved for errors.
+ // Order is weird for historical reasons.
+ TYPE_DOUBLE = 1;
+ TYPE_FLOAT = 2;
+ // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
+ // negative values are likely.
+ TYPE_INT64 = 3;
+ TYPE_UINT64 = 4;
+ // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
+ // negative values are likely.
+ TYPE_INT32 = 5;
+ TYPE_FIXED64 = 6;
+ TYPE_FIXED32 = 7;
+ TYPE_BOOL = 8;
+ TYPE_STRING = 9;
+ // Tag-delimited aggregate.
+ // Group type is deprecated and not supported in proto3. However, Proto3
+ // implementations should still be able to parse the group wire format and
+ // treat group fields as unknown fields.
+ TYPE_GROUP = 10;
+ TYPE_MESSAGE = 11; // Length-delimited aggregate.
+
+ // New in version 2.
+ TYPE_BYTES = 12;
+ TYPE_UINT32 = 13;
+ TYPE_ENUM = 14;
+ TYPE_SFIXED32 = 15;
+ TYPE_SFIXED64 = 16;
+ TYPE_SINT32 = 17; // Uses ZigZag encoding.
+ TYPE_SINT64 = 18; // Uses ZigZag encoding.
+ }
+
+ enum Label {
+ // 0 is reserved for errors
+ LABEL_OPTIONAL = 1;
+ LABEL_REQUIRED = 2;
+ LABEL_REPEATED = 3;
+ }
+
+ optional string name = 1;
+ optional int32 number = 3;
+ optional Label label = 4;
+
+ // If type_name is set, this need not be set. If both this and type_name
+ // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
+ optional Type type = 5;
+
+ // For message and enum types, this is the name of the type. If the name
+ // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
+ // rules are used to find the type (i.e. first the nested types within this
+ // message are searched, then within the parent, on up to the root
+ // namespace).
+ optional string type_name = 6;
+
+ // For extensions, this is the name of the type being extended. It is
+ // resolved in the same manner as type_name.
+ optional string extendee = 2;
+
+ // For numeric types, contains the original text representation of the value.
+ // For booleans, "true" or "false".
+ // For strings, contains the default text contents (not escaped in any way).
+ // For bytes, contains the C escaped value. All bytes >= 128 are escaped.
+ optional string default_value = 7;
+
+ // If set, gives the index of a oneof in the containing type's oneof_decl
+ // list. This field is a member of that oneof.
+ optional int32 oneof_index = 9;
+
+ // JSON name of this field. The value is set by protocol compiler. If the
+ // user has set a "json_name" option on this field, that option's value
+ // will be used. Otherwise, it's deduced from the field's name by converting
+ // it to camelCase.
+ optional string json_name = 10;
+
+ optional FieldOptions options = 8;
+
+ // If true, this is a proto3 "optional". When a proto3 field is optional, it
+ // tracks presence regardless of field type.
+ //
+ // When proto3_optional is true, this field must be belong to a oneof to
+ // signal to old proto3 clients that presence is tracked for this field. This
+ // oneof is known as a "synthetic" oneof, and this field must be its sole
+ // member (each proto3 optional field gets its own synthetic oneof). Synthetic
+ // oneofs exist in the descriptor only, and do not generate any API. Synthetic
+ // oneofs must be ordered after all "real" oneofs.
+ //
+ // For message fields, proto3_optional doesn't create any semantic change,
+ // since non-repeated message fields always track presence. However it still
+ // indicates the semantic detail of whether the user wrote "optional" or not.
+ // This can be useful for round-tripping the .proto file. For consistency we
+ // give message fields a synthetic oneof also, even though it is not required
+ // to track presence. This is especially important because the parser can't
+ // tell if a field is a message or an enum, so it must always create a
+ // synthetic oneof.
+ //
+ // Proto2 optional fields do not set this flag, because they already indicate
+ // optional with `LABEL_OPTIONAL`.
+ optional bool proto3_optional = 17;
+}
+
+// Describes a oneof.
+message OneofDescriptorProto {
+ optional string name = 1;
+ optional OneofOptions options = 2;
+}
+
+// Describes an enum type.
+message EnumDescriptorProto {
+ optional string name = 1;
+
+ repeated EnumValueDescriptorProto value = 2;
+
+ optional EnumOptions options = 3;
+
+ // Range of reserved numeric values. Reserved values may not be used by
+ // entries in the same enum. Reserved ranges may not overlap.
+ //
+ // Note that this is distinct from DescriptorProto.ReservedRange in that it
+ // is inclusive such that it can appropriately represent the entire int32
+ // domain.
+ message EnumReservedRange {
+ optional int32 start = 1; // Inclusive.
+ optional int32 end = 2; // Inclusive.
+ }
+
+ // Range of reserved numeric values. Reserved numeric values may not be used
+ // by enum values in the same enum declaration. Reserved ranges may not
+ // overlap.
+ repeated EnumReservedRange reserved_range = 4;
+
+ // Reserved enum value names, which may not be reused. A given name may only
+ // be reserved once.
+ repeated string reserved_name = 5;
+}
+
+// Describes a value within an enum.
+message EnumValueDescriptorProto {
+ optional string name = 1;
+ optional int32 number = 2;
+
+ optional EnumValueOptions options = 3;
+}
+
+// Describes a service.
+message ServiceDescriptorProto {
+ optional string name = 1;
+ repeated MethodDescriptorProto method = 2;
+
+ optional ServiceOptions options = 3;
+}
+
+// Describes a method of a service.
+message MethodDescriptorProto {
+ optional string name = 1;
+
+ // Input and output type names. These are resolved in the same way as
+ // FieldDescriptorProto.type_name, but must refer to a message type.
+ optional string input_type = 2;
+ optional string output_type = 3;
+
+ optional MethodOptions options = 4;
+
+ // Identifies if client streams multiple client messages
+ optional bool client_streaming = 5 [default = false];
+ // Identifies if server streams multiple server messages
+ optional bool server_streaming = 6 [default = false];
+}
+
+// ===================================================================
+// Options
+
+// Each of the definitions above may have "options" attached. These are
+// just annotations which may cause code to be generated slightly differently
+// or may contain hints for code that manipulates protocol messages.
+//
+// Clients may define custom options as extensions of the *Options messages.
+// These extensions may not yet be known at parsing time, so the parser cannot
+// store the values in them. Instead it stores them in a field in the *Options
+// message called uninterpreted_option. This field must have the same name
+// across all *Options messages. We then use this field to populate the
+// extensions when we build a descriptor, at which point all protos have been
+// parsed and so all extensions are known.
+//
+// Extension numbers for custom options may be chosen as follows:
+// * For options which will only be used within a single application or
+// organization, or for experimental options, use field numbers 50000
+// through 99999. It is up to you to ensure that you do not use the
+// same number for multiple options.
+// * For options which will be published and used publicly by multiple
+// independent entities, e-mail protobuf-global-extension-registry@google.com
+// to reserve extension numbers. Simply provide your project name (e.g.
+// Objective-C plugin) and your project website (if available) -- there's no
+// need to explain how you intend to use them. Usually you only need one
+// extension number. You can declare multiple options with only one extension
+// number by putting them in a sub-message. See the Custom Options section of
+// the docs for examples:
+// https://developers.google.com/protocol-buffers/docs/proto#options
+// If this turns out to be popular, a web service will be set up
+// to automatically assign option numbers.
+
+message FileOptions {
+
+ // Sets the Java package where classes generated from this .proto will be
+ // placed. By default, the proto package is used, but this is often
+ // inappropriate because proto packages do not normally start with backwards
+ // domain names.
+ optional string java_package = 1;
+
+ // Controls the name of the wrapper Java class generated for the .proto file.
+ // That class will always contain the .proto file's getDescriptor() method as
+ // well as any top-level extensions defined in the .proto file.
+ // If java_multiple_files is disabled, then all the other classes from the
+ // .proto file will be nested inside the single wrapper outer class.
+ optional string java_outer_classname = 8;
+
+ // If enabled, then the Java code generator will generate a separate .java
+ // file for each top-level message, enum, and service defined in the .proto
+ // file. Thus, these types will *not* be nested inside the wrapper class
+ // named by java_outer_classname. However, the wrapper class will still be
+ // generated to contain the file's getDescriptor() method as well as any
+ // top-level extensions defined in the file.
+ optional bool java_multiple_files = 10 [default = false];
+
+ // This option does nothing.
+ optional bool java_generate_equals_and_hash = 20 [deprecated=true];
+
+ // If set true, then the Java2 code generator will generate code that
+ // throws an exception whenever an attempt is made to assign a non-UTF-8
+ // byte sequence to a string field.
+ // Message reflection will do the same.
+ // However, an extension field still accepts non-UTF-8 byte sequences.
+ // This option has no effect on when used with the lite runtime.
+ optional bool java_string_check_utf8 = 27 [default = false];
+
+ // Generated classes can be optimized for speed or code size.
+ enum OptimizeMode {
+ SPEED = 1; // Generate complete code for parsing, serialization,
+ // etc.
+ CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
+ LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
+ }
+ optional OptimizeMode optimize_for = 9 [default = SPEED];
+
+ // Sets the Go package where structs generated from this .proto will be
+ // placed. If omitted, the Go package will be derived from the following:
+ // - The basename of the package import path, if provided.
+ // - Otherwise, the package statement in the .proto file, if present.
+ // - Otherwise, the basename of the .proto file, without extension.
+ optional string go_package = 11;
+
+ // Should generic services be generated in each language? "Generic" services
+ // are not specific to any particular RPC system. They are generated by the
+ // main code generators in each language (without additional plugins).
+ // Generic services were the only kind of service generation supported by
+ // early versions of google.protobuf.
+ //
+ // Generic services are now considered deprecated in favor of using plugins
+ // that generate code specific to your particular RPC system. Therefore,
+ // these default to false. Old code which depends on generic services should
+ // explicitly set them to true.
+ optional bool cc_generic_services = 16 [default = false];
+ optional bool java_generic_services = 17 [default = false];
+ optional bool py_generic_services = 18 [default = false];
+ optional bool php_generic_services = 42 [default = false];
+
+ // Is this file deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for everything in the file, or it will be completely ignored; in the very
+ // least, this is a formalization for deprecating files.
+ optional bool deprecated = 23 [default = false];
+
+ // Enables the use of arenas for the proto messages in this file. This applies
+ // only to generated classes for C++.
+ optional bool cc_enable_arenas = 31 [default = true];
+
+ // Sets the objective c class prefix which is prepended to all objective c
+ // generated classes from this .proto. There is no default.
+ optional string objc_class_prefix = 36;
+
+ // Namespace for generated classes; defaults to the package.
+ optional string csharp_namespace = 37;
+
+ // By default Swift generators will take the proto package and CamelCase it
+ // replacing '.' with underscore and use that to prefix the types/symbols
+ // defined. When this options is provided, they will use this value instead
+ // to prefix the types/symbols defined.
+ optional string swift_prefix = 39;
+
+ // Sets the php class prefix which is prepended to all php generated classes
+ // from this .proto. Default is empty.
+ optional string php_class_prefix = 40;
+
+ // Use this option to change the namespace of php generated classes. Default
+ // is empty. When this option is empty, the package name will be used for
+ // determining the namespace.
+ optional string php_namespace = 41;
+
+ // Use this option to change the namespace of php generated metadata classes.
+ // Default is empty. When this option is empty, the proto file name will be
+ // used for determining the namespace.
+ optional string php_metadata_namespace = 44;
+
+ // Use this option to change the package of ruby generated classes. Default
+ // is empty. When this option is not set, the package name will be used for
+ // determining the ruby package.
+ optional string ruby_package = 45;
+
+ // The parser stores options it doesn't recognize here.
+ // See the documentation for the "Options" section above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message.
+ // See the documentation for the "Options" section above.
+ extensions 1000 to max;
+
+ reserved 38;
+}
+
+message MessageOptions {
+ // Set true to use the old proto1 MessageSet wire format for extensions.
+ // This is provided for backwards-compatibility with the MessageSet wire
+ // format. You should not use this for any other reason: It's less
+ // efficient, has fewer features, and is more complicated.
+ //
+ // The message must be defined exactly as follows:
+ // message Foo {
+ // option message_set_wire_format = true;
+ // extensions 4 to max;
+ // }
+ // Note that the message cannot have any defined fields; MessageSets only
+ // have extensions.
+ //
+ // All extensions of your type must be singular messages; e.g. they cannot
+ // be int32s, enums, or repeated messages.
+ //
+ // Because this is an option, the above two restrictions are not enforced by
+ // the protocol compiler.
+ optional bool message_set_wire_format = 1 [default = false];
+
+ // Disables the generation of the standard "descriptor()" accessor, which can
+ // conflict with a field of the same name. This is meant to make migration
+ // from proto1 easier; new code should avoid fields named "descriptor".
+ optional bool no_standard_descriptor_accessor = 2 [default = false];
+
+ // Is this message deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the message, or it will be completely ignored; in the very least,
+ // this is a formalization for deprecating messages.
+ optional bool deprecated = 3 [default = false];
+
+ reserved 4, 5, 6;
+
+ // NOTE: Do not set the option in .proto files. Always use the maps syntax
+ // instead. The option should only be implicitly set by the proto compiler
+ // parser.
+ //
+ // Whether the message is an automatically generated map entry type for the
+ // maps field.
+ //
+ // For maps fields:
+ // map map_field = 1;
+ // The parsed descriptor looks like:
+ // message MapFieldEntry {
+ // option map_entry = true;
+ // optional KeyType key = 1;
+ // optional ValueType value = 2;
+ // }
+ // repeated MapFieldEntry map_field = 1;
+ //
+ // Implementations may choose not to generate the map_entry=true message, but
+ // use a native map in the target language to hold the keys and values.
+ // The reflection APIs in such implementations still need to work as
+ // if the field is a repeated message field.
+ optional bool map_entry = 7;
+
+ reserved 8; // javalite_serializable
+ reserved 9; // javanano_as_lite
+
+ // Enable the legacy handling of JSON field name conflicts. This lowercases
+ // and strips underscored from the fields before comparison in proto3 only.
+ // The new behavior takes `json_name` into account and applies to proto2 as
+ // well.
+ //
+ // This should only be used as a temporary measure against broken builds due
+ // to the change in behavior for JSON field name conflicts.
+ //
+ // TODO(b/261750190) This is legacy behavior we plan to remove once downstream
+ // teams have had time to migrate.
+ optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true];
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+message FieldOptions {
+ // The ctype option instructs the C++ code generator to use a different
+ // representation of the field than it normally would. See the specific
+ // options below. This option is not yet implemented in the open source
+ // release -- sorry, we'll try to include it in a future version!
+ optional CType ctype = 1 [default = STRING];
+ enum CType {
+ // Default mode.
+ STRING = 0;
+
+ CORD = 1;
+
+ STRING_PIECE = 2;
+ }
+ // The packed option can be enabled for repeated primitive fields to enable
+ // a more efficient representation on the wire. Rather than repeatedly
+ // writing the tag and type for each element, the entire array is encoded as
+ // a single length-delimited blob. In proto3, only explicit setting it to
+ // false will avoid using packed encoding.
+ optional bool packed = 2;
+
+ // The jstype option determines the JavaScript type used for values of the
+ // field. The option is permitted only for 64 bit integral and fixed types
+ // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
+ // is represented as JavaScript string, which avoids loss of precision that
+ // can happen when a large value is converted to a floating point JavaScript.
+ // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
+ // use the JavaScript "number" type. The behavior of the default option
+ // JS_NORMAL is implementation dependent.
+ //
+ // This option is an enum to permit additional types to be added, e.g.
+ // goog.math.Integer.
+ optional JSType jstype = 6 [default = JS_NORMAL];
+ enum JSType {
+ // Use the default type.
+ JS_NORMAL = 0;
+
+ // Use JavaScript strings.
+ JS_STRING = 1;
+
+ // Use JavaScript numbers.
+ JS_NUMBER = 2;
+ }
+
+ // Should this field be parsed lazily? Lazy applies only to message-type
+ // fields. It means that when the outer message is initially parsed, the
+ // inner message's contents will not be parsed but instead stored in encoded
+ // form. The inner message will actually be parsed when it is first accessed.
+ //
+ // This is only a hint. Implementations are free to choose whether to use
+ // eager or lazy parsing regardless of the value of this option. However,
+ // setting this option true suggests that the protocol author believes that
+ // using lazy parsing on this field is worth the additional bookkeeping
+ // overhead typically needed to implement it.
+ //
+ // This option does not affect the public interface of any generated code;
+ // all method signatures remain the same. Furthermore, thread-safety of the
+ // interface is not affected by this option; const methods remain safe to
+ // call from multiple threads concurrently, while non-const methods continue
+ // to require exclusive access.
+ //
+ // Note that implementations may choose not to check required fields within
+ // a lazy sub-message. That is, calling IsInitialized() on the outer message
+ // may return true even if the inner message has missing required fields.
+ // This is necessary because otherwise the inner message would have to be
+ // parsed in order to perform the check, defeating the purpose of lazy
+ // parsing. An implementation which chooses not to check required fields
+ // must be consistent about it. That is, for any particular sub-message, the
+ // implementation must either *always* check its required fields, or *never*
+ // check its required fields, regardless of whether or not the message has
+ // been parsed.
+ //
+ // As of May 2022, lazy verifies the contents of the byte stream during
+ // parsing. An invalid byte stream will cause the overall parsing to fail.
+ optional bool lazy = 5 [default = false];
+
+ // unverified_lazy does no correctness checks on the byte stream. This should
+ // only be used where lazy with verification is prohibitive for performance
+ // reasons.
+ optional bool unverified_lazy = 15 [default = false];
+
+ // Is this field deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for accessors, or it will be completely ignored; in the very least, this
+ // is a formalization for deprecating fields.
+ optional bool deprecated = 3 [default = false];
+
+ // For Google-internal migration only. Do not use.
+ optional bool weak = 10 [default = false];
+
+ // Indicate that the field value should not be printed out when using debug
+ // formats, e.g. when the field contains sensitive credentials.
+ optional bool debug_redact = 16 [default = false];
+
+ // If set to RETENTION_SOURCE, the option will be omitted from the binary.
+ // Note: as of January 2023, support for this is in progress and does not yet
+ // have an effect (b/264593489).
+ enum OptionRetention {
+ RETENTION_UNKNOWN = 0;
+ RETENTION_RUNTIME = 1;
+ RETENTION_SOURCE = 2;
+ }
+
+ optional OptionRetention retention = 17;
+
+ // This indicates the types of entities that the field may apply to when used
+ // as an option. If it is unset, then the field may be freely used as an
+ // option on any kind of entity. Note: as of January 2023, support for this is
+ // in progress and does not yet have an effect (b/264593489).
+ enum OptionTargetType {
+ TARGET_TYPE_UNKNOWN = 0;
+ TARGET_TYPE_FILE = 1;
+ TARGET_TYPE_EXTENSION_RANGE = 2;
+ TARGET_TYPE_MESSAGE = 3;
+ TARGET_TYPE_FIELD = 4;
+ TARGET_TYPE_ONEOF = 5;
+ TARGET_TYPE_ENUM = 6;
+ TARGET_TYPE_ENUM_ENTRY = 7;
+ TARGET_TYPE_SERVICE = 8;
+ TARGET_TYPE_METHOD = 9;
+ }
+
+ optional OptionTargetType target = 18;
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+
+ reserved 4; // removed jtype
+}
+
+message OneofOptions {
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+message EnumOptions {
+
+ // Set this option to true to allow mapping different tag names to the same
+ // value.
+ optional bool allow_alias = 2;
+
+ // Is this enum deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the enum, or it will be completely ignored; in the very least, this
+ // is a formalization for deprecating enums.
+ optional bool deprecated = 3 [default = false];
+
+ reserved 5; // javanano_as_lite
+
+ // Enable the legacy handling of JSON field name conflicts. This lowercases
+ // and strips underscored from the fields before comparison in proto3 only.
+ // The new behavior takes `json_name` into account and applies to proto2 as
+ // well.
+ // TODO(b/261750190) Remove this legacy behavior once downstream teams have
+ // had time to migrate.
+ optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true];
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+message EnumValueOptions {
+ // Is this enum value deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the enum value, or it will be completely ignored; in the very least,
+ // this is a formalization for deprecating enum values.
+ optional bool deprecated = 1 [default = false];
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+message ServiceOptions {
+
+ // Note: Field numbers 1 through 32 are reserved for Google's internal RPC
+ // framework. We apologize for hoarding these numbers to ourselves, but
+ // we were already using them long before we decided to release Protocol
+ // Buffers.
+
+ // Is this service deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the service, or it will be completely ignored; in the very least,
+ // this is a formalization for deprecating services.
+ optional bool deprecated = 33 [default = false];
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+message MethodOptions {
+
+ // Note: Field numbers 1 through 32 are reserved for Google's internal RPC
+ // framework. We apologize for hoarding these numbers to ourselves, but
+ // we were already using them long before we decided to release Protocol
+ // Buffers.
+
+ // Is this method deprecated?
+ // Depending on the target platform, this can emit Deprecated annotations
+ // for the method, or it will be completely ignored; in the very least,
+ // this is a formalization for deprecating methods.
+ optional bool deprecated = 33 [default = false];
+
+ // Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
+ // or neither? HTTP based RPC implementation may choose GET verb for safe
+ // methods, and PUT verb for idempotent methods instead of the default POST.
+ enum IdempotencyLevel {
+ IDEMPOTENCY_UNKNOWN = 0;
+ NO_SIDE_EFFECTS = 1; // implies idempotent
+ IDEMPOTENT = 2; // idempotent, but may have side effects
+ }
+ optional IdempotencyLevel idempotency_level = 34
+ [default = IDEMPOTENCY_UNKNOWN];
+
+ // The parser stores options it doesn't recognize here. See above.
+ repeated UninterpretedOption uninterpreted_option = 999;
+
+ // Clients can define custom options in extensions of this message. See above.
+ extensions 1000 to max;
+}
+
+// A message representing a option the parser does not recognize. This only
+// appears in options protos created by the compiler::Parser class.
+// DescriptorPool resolves these when building Descriptor objects. Therefore,
+// options protos in descriptor objects (e.g. returned by Descriptor::options(),
+// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
+// in them.
+message UninterpretedOption {
+ // The name of the uninterpreted option. Each string represents a segment in
+ // a dot-separated name. is_extension is true iff a segment represents an
+ // extension (denoted with parentheses in options specs in .proto files).
+ // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents
+ // "foo.(bar.baz).moo".
+ message NamePart {
+ required string name_part = 1;
+ required bool is_extension = 2;
+ }
+ repeated NamePart name = 2;
+
+ // The value of the uninterpreted option, in whatever type the tokenizer
+ // identified it as during parsing. Exactly one of these should be set.
+ optional string identifier_value = 3;
+ optional uint64 positive_int_value = 4;
+ optional int64 negative_int_value = 5;
+ optional double double_value = 6;
+ optional bytes string_value = 7;
+ optional string aggregate_value = 8;
+}
+
+// ===================================================================
+// Optional source code info
+
+// Encapsulates information about the original source file from which a
+// FileDescriptorProto was generated.
+message SourceCodeInfo {
+ // A Location identifies a piece of source code in a .proto file which
+ // corresponds to a particular definition. This information is intended
+ // to be useful to IDEs, code indexers, documentation generators, and similar
+ // tools.
+ //
+ // For example, say we have a file like:
+ // message Foo {
+ // optional string foo = 1;
+ // }
+ // Let's look at just the field definition:
+ // optional string foo = 1;
+ // ^ ^^ ^^ ^ ^^^
+ // a bc de f ghi
+ // We have the following locations:
+ // span path represents
+ // [a,i) [ 4, 0, 2, 0 ] The whole field definition.
+ // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional).
+ // [c,d) [ 4, 0, 2, 0, 5 ] The type (string).
+ // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo).
+ // [g,h) [ 4, 0, 2, 0, 3 ] The number (1).
+ //
+ // Notes:
+ // - A location may refer to a repeated field itself (i.e. not to any
+ // particular index within it). This is used whenever a set of elements are
+ // logically enclosed in a single code segment. For example, an entire
+ // extend block (possibly containing multiple extension definitions) will
+ // have an outer location whose path refers to the "extensions" repeated
+ // field without an index.
+ // - Multiple locations may have the same path. This happens when a single
+ // logical declaration is spread out across multiple places. The most
+ // obvious example is the "extend" block again -- there may be multiple
+ // extend blocks in the same scope, each of which will have the same path.
+ // - A location's span is not always a subset of its parent's span. For
+ // example, the "extendee" of an extension declaration appears at the
+ // beginning of the "extend" block and is shared by all extensions within
+ // the block.
+ // - Just because a location's span is a subset of some other location's span
+ // does not mean that it is a descendant. For example, a "group" defines
+ // both a type and a field in a single declaration. Thus, the locations
+ // corresponding to the type and field and their components will overlap.
+ // - Code which tries to interpret locations should probably be designed to
+ // ignore those that it doesn't understand, as more types of locations could
+ // be recorded in the future.
+ repeated Location location = 1;
+ message Location {
+ // Identifies which part of the FileDescriptorProto was defined at this
+ // location.
+ //
+ // Each element is a field number or an index. They form a path from
+ // the root FileDescriptorProto to the place where the definition occurs.
+ // For example, this path:
+ // [ 4, 3, 2, 7, 1 ]
+ // refers to:
+ // file.message_type(3) // 4, 3
+ // .field(7) // 2, 7
+ // .name() // 1
+ // This is because FileDescriptorProto.message_type has field number 4:
+ // repeated DescriptorProto message_type = 4;
+ // and DescriptorProto.field has field number 2:
+ // repeated FieldDescriptorProto field = 2;
+ // and FieldDescriptorProto.name has field number 1:
+ // optional string name = 1;
+ //
+ // Thus, the above path gives the location of a field name. If we removed
+ // the last element:
+ // [ 4, 3, 2, 7 ]
+ // this path refers to the whole field declaration (from the beginning
+ // of the label to the terminating semicolon).
+ repeated int32 path = 1 [packed = true];
+
+ // Always has exactly three or four elements: start line, start column,
+ // end line (optional, otherwise assumed same as start line), end column.
+ // These are packed into a single field for efficiency. Note that line
+ // and column numbers are zero-based -- typically you will want to add
+ // 1 to each before displaying to a user.
+ repeated int32 span = 2 [packed = true];
+
+ // If this SourceCodeInfo represents a complete declaration, these are any
+ // comments appearing before and after the declaration which appear to be
+ // attached to the declaration.
+ //
+ // A series of line comments appearing on consecutive lines, with no other
+ // tokens appearing on those lines, will be treated as a single comment.
+ //
+ // leading_detached_comments will keep paragraphs of comments that appear
+ // before (but not connected to) the current element. Each paragraph,
+ // separated by empty lines, will be one comment element in the repeated
+ // field.
+ //
+ // Only the comment content is provided; comment markers (e.g. //) are
+ // stripped out. For block comments, leading whitespace and an asterisk
+ // will be stripped from the beginning of each line other than the first.
+ // Newlines are included in the output.
+ //
+ // Examples:
+ //
+ // optional int32 foo = 1; // Comment attached to foo.
+ // // Comment attached to bar.
+ // optional int32 bar = 2;
+ //
+ // optional string baz = 3;
+ // // Comment attached to baz.
+ // // Another line attached to baz.
+ //
+ // // Comment attached to moo.
+ // //
+ // // Another line attached to moo.
+ // optional double moo = 4;
+ //
+ // // Detached comment for corge. This is not leading or trailing comments
+ // // to moo or corge because there are blank lines separating it from
+ // // both.
+ //
+ // // Detached comment for corge paragraph 2.
+ //
+ // optional string corge = 5;
+ // /* Block comment attached
+ // * to corge. Leading asterisks
+ // * will be removed. */
+ // /* Block comment attached to
+ // * grault. */
+ // optional int32 grault = 6;
+ //
+ // // ignored detached comments.
+ optional string leading_comments = 3;
+ optional string trailing_comments = 4;
+ repeated string leading_detached_comments = 6;
+ }
+}
+
+// Describes the relationship between generated code and its original source
+// file. A GeneratedCodeInfo message is associated with only one generated
+// source file, but may contain references to different source .proto files.
+message GeneratedCodeInfo {
+ // An Annotation connects some span of text in generated code to an element
+ // of its generating .proto file.
+ repeated Annotation annotation = 1;
+ message Annotation {
+ // Identifies the element in the original source .proto file. This field
+ // is formatted the same as SourceCodeInfo.Location.path.
+ repeated int32 path = 1 [packed = true];
+
+ // Identifies the filesystem path to the original source .proto.
+ optional string source_file = 2;
+
+ // Identifies the starting offset in bytes in the generated code
+ // that relates to the identified object.
+ optional int32 begin = 3;
+
+ // Identifies the ending offset in bytes in the generated code that
+ // relates to the identified object. The end offset should be one past
+ // the last relevant byte (so the length of the text = end - begin).
+ optional int32 end = 4;
+
+ // Represents the identified object's effect on the element in the original
+ // .proto file.
+ enum Semantic {
+ // There is no effect or the effect is indescribable.
+ NONE = 0;
+ // The element is set or otherwise mutated.
+ SET = 1;
+ // An alias to the element is returned.
+ ALIAS = 2;
+ }
+ optional Semantic semantic = 5;
+ }
+}
diff --git a/example/google/protobuf/empty.proto b/example/google/protobuf/empty.proto
new file mode 100644
index 0000000..2211524
--- /dev/null
+++ b/example/google/protobuf/empty.proto
@@ -0,0 +1,51 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option go_package = "google.golang.org/protobuf/types/known/emptypb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "EmptyProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+
+// A generic empty message that you can re-use to avoid defining duplicated
+// empty messages in your APIs. A typical example is to use it as the request
+// or the response type of an API method. For instance:
+//
+// service Foo {
+// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
+// }
+//
+message Empty {}
\ No newline at end of file
diff --git a/example/google/protobuf/field_mask.proto b/example/google/protobuf/field_mask.proto
new file mode 100755
index 0000000..b28334b
--- /dev/null
+++ b/example/google/protobuf/field_mask.proto
@@ -0,0 +1,245 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option java_package = "com.google.protobuf";
+option java_outer_classname = "FieldMaskProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb";
+option cc_enable_arenas = true;
+
+// `FieldMask` represents a set of symbolic field paths, for example:
+//
+// paths: "f.a"
+// paths: "f.b.d"
+//
+// Here `f` represents a field in some root message, `a` and `b`
+// fields in the message found in `f`, and `d` a field found in the
+// message in `f.b`.
+//
+// Field masks are used to specify a subset of fields that should be
+// returned by a get operation or modified by an update operation.
+// Field masks also have a custom JSON encoding (see below).
+//
+// # Field Masks in Projections
+//
+// When used in the context of a projection, a response message or
+// sub-message is filtered by the API to only contain those fields as
+// specified in the mask. For example, if the mask in the previous
+// example is applied to a response message as follows:
+//
+// f {
+// a : 22
+// b {
+// d : 1
+// x : 2
+// }
+// y : 13
+// }
+// z: 8
+//
+// The result will not contain specific values for fields x,y and z
+// (their value will be set to the default, and omitted in proto text
+// output):
+//
+//
+// f {
+// a : 22
+// b {
+// d : 1
+// }
+// }
+//
+// A repeated field is not allowed except at the last position of a
+// paths string.
+//
+// If a FieldMask object is not present in a get operation, the
+// operation applies to all fields (as if a FieldMask of all fields
+// had been specified).
+//
+// Note that a field mask does not necessarily apply to the
+// top-level response message. In case of a REST get operation, the
+// field mask applies directly to the response, but in case of a REST
+// list operation, the mask instead applies to each individual message
+// in the returned resource list. In case of a REST custom method,
+// other definitions may be used. Where the mask applies will be
+// clearly documented together with its declaration in the API. In
+// any case, the effect on the returned resource/resources is required
+// behavior for APIs.
+//
+// # Field Masks in Update Operations
+//
+// A field mask in update operations specifies which fields of the
+// targeted resource are going to be updated. The API is required
+// to only change the values of the fields as specified in the mask
+// and leave the others untouched. If a resource is passed in to
+// describe the updated values, the API ignores the values of all
+// fields not covered by the mask.
+//
+// If a repeated field is specified for an update operation, new values will
+// be appended to the existing repeated field in the target resource. Note that
+// a repeated field is only allowed in the last position of a `paths` string.
+//
+// If a sub-message is specified in the last position of the field mask for an
+// update operation, then new value will be merged into the existing sub-message
+// in the target resource.
+//
+// For example, given the target message:
+//
+// f {
+// b {
+// d: 1
+// x: 2
+// }
+// c: [1]
+// }
+//
+// And an update message:
+//
+// f {
+// b {
+// d: 10
+// }
+// c: [2]
+// }
+//
+// then if the field mask is:
+//
+// paths: ["f.b", "f.c"]
+//
+// then the result will be:
+//
+// f {
+// b {
+// d: 10
+// x: 2
+// }
+// c: [1, 2]
+// }
+//
+// An implementation may provide options to override this default behavior for
+// repeated and message fields.
+//
+// In order to reset a field's value to the default, the field must
+// be in the mask and set to the default value in the provided resource.
+// Hence, in order to reset all fields of a resource, provide a default
+// instance of the resource and set all fields in the mask, or do
+// not provide a mask as described below.
+//
+// If a field mask is not present on update, the operation applies to
+// all fields (as if a field mask of all fields has been specified).
+// Note that in the presence of schema evolution, this may mean that
+// fields the client does not know and has therefore not filled into
+// the request will be reset to their default. If this is unwanted
+// behavior, a specific service may require a client to always specify
+// a field mask, producing an error if not.
+//
+// As with get operations, the location of the resource which
+// describes the updated values in the request message depends on the
+// operation kind. In any case, the effect of the field mask is
+// required to be honored by the API.
+//
+// ## Considerations for HTTP REST
+//
+// The HTTP kind of an update operation which uses a field mask must
+// be set to PATCH instead of PUT in order to satisfy HTTP semantics
+// (PUT must only be used for full updates).
+//
+// # JSON Encoding of Field Masks
+//
+// In JSON, a field mask is encoded as a single string where paths are
+// separated by a comma. Fields name in each path are converted
+// to/from lower-camel naming conventions.
+//
+// As an example, consider the following message declarations:
+//
+// message Profile {
+// User user = 1;
+// Photo photo = 2;
+// }
+// message User {
+// string display_name = 1;
+// string address = 2;
+// }
+//
+// In proto a field mask for `Profile` may look as such:
+//
+// mask {
+// paths: "user.display_name"
+// paths: "photo"
+// }
+//
+// In JSON, the same mask is represented as below:
+//
+// {
+// mask: "user.displayName,photo"
+// }
+//
+// # Field Masks and Oneof Fields
+//
+// Field masks treat fields in oneofs just as regular fields. Consider the
+// following message:
+//
+// message SampleMessage {
+// oneof test_oneof {
+// string name = 4;
+// SubMessage sub_message = 9;
+// }
+// }
+//
+// The field mask can be:
+//
+// mask {
+// paths: "name"
+// }
+//
+// Or:
+//
+// mask {
+// paths: "sub_message"
+// }
+//
+// Note that oneof type names ("test_oneof" in this case) cannot be used in
+// paths.
+//
+// ## Field Mask Verification
+//
+// The implementation of any API method which has a FieldMask type field in the
+// request should verify the included field paths, and return an
+// `INVALID_ARGUMENT` error if any path is unmappable.
+message FieldMask {
+ // The set of field mask paths.
+ repeated string paths = 1;
+}
diff --git a/example/google/protobuf/struct.proto b/example/google/protobuf/struct.proto
new file mode 100644
index 0000000..e07e343
--- /dev/null
+++ b/example/google/protobuf/struct.proto
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/protobuf/types/known/structpb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "StructProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+
+// `Struct` represents a structured data value, consisting of fields
+// which map to dynamically typed values. In some languages, `Struct`
+// might be supported by a native representation. For example, in
+// scripting languages like JS a struct is represented as an
+// object. The details of that representation are described together
+// with the proto support for the language.
+//
+// The JSON representation for `Struct` is JSON object.
+message Struct {
+ // Unordered map of dynamically typed values.
+ map fields = 1;
+}
+
+// `Value` represents a dynamically typed value which can be either
+// null, a number, a string, a boolean, a recursive struct value, or a
+// list of values. A producer of value is expected to set one of these
+// variants. Absence of any variant indicates an error.
+//
+// The JSON representation for `Value` is JSON value.
+message Value {
+ // The kind of value.
+ oneof kind {
+ // Represents a null value.
+ NullValue null_value = 1;
+ // Represents a double value.
+ double number_value = 2;
+ // Represents a string value.
+ string string_value = 3;
+ // Represents a boolean value.
+ bool bool_value = 4;
+ // Represents a structured value.
+ Struct struct_value = 5;
+ // Represents a repeated `Value`.
+ ListValue list_value = 6;
+ }
+}
+
+// `NullValue` is a singleton enumeration to represent the null value for the
+// `Value` type union.
+//
+// The JSON representation for `NullValue` is JSON `null`.
+enum NullValue {
+ // Null value.
+ NULL_VALUE = 0;
+}
+
+// `ListValue` is a wrapper around a repeated field of values.
+//
+// The JSON representation for `ListValue` is JSON array.
+message ListValue {
+ // Repeated field of dynamically typed values.
+ repeated Value values = 1;
+}
\ No newline at end of file
diff --git a/example/google/protobuf/timestamp.proto b/example/google/protobuf/timestamp.proto
new file mode 100755
index 0000000..2fb527c
--- /dev/null
+++ b/example/google/protobuf/timestamp.proto
@@ -0,0 +1,144 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/protobuf/types/known/timestamppb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TimestampProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+
+// A Timestamp represents a point in time independent of any time zone or local
+// calendar, encoded as a count of seconds and fractions of seconds at
+// nanosecond resolution. The count is relative to an epoch at UTC midnight on
+// January 1, 1970, in the proleptic Gregorian calendar which extends the
+// Gregorian calendar backwards to year one.
+//
+// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
+// second table is needed for interpretation, using a [24-hour linear
+// smear](https://developers.google.com/time/smear).
+//
+// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
+// restricting to that range, we ensure that we can convert to and from [RFC
+// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
+//
+// # Examples
+//
+// Example 1: Compute Timestamp from POSIX `time()`.
+//
+// Timestamp timestamp;
+// timestamp.set_seconds(time(NULL));
+// timestamp.set_nanos(0);
+//
+// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
+//
+// struct timeval tv;
+// gettimeofday(&tv, NULL);
+//
+// Timestamp timestamp;
+// timestamp.set_seconds(tv.tv_sec);
+// timestamp.set_nanos(tv.tv_usec * 1000);
+//
+// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+//
+// FILETIME ft;
+// GetSystemTimeAsFileTime(&ft);
+// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
+//
+// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
+// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
+// Timestamp timestamp;
+// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
+// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
+//
+// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
+//
+// long millis = System.currentTimeMillis();
+//
+// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
+// .setNanos((int) ((millis % 1000) * 1000000)).build();
+//
+// Example 5: Compute Timestamp from Java `Instant.now()`.
+//
+// Instant now = Instant.now();
+//
+// Timestamp timestamp =
+// Timestamp.newBuilder().setSeconds(now.getEpochSecond())
+// .setNanos(now.getNano()).build();
+//
+// Example 6: Compute Timestamp from current time in Python.
+//
+// timestamp = Timestamp()
+// timestamp.GetCurrentTime()
+//
+// # JSON Mapping
+//
+// In JSON format, the Timestamp type is encoded as a string in the
+// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
+// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
+// where {year} is always expressed using four digits while {month}, {day},
+// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
+// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
+// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
+// is required. A proto3 JSON serializer should always use UTC (as indicated by
+// "Z") when printing the Timestamp type and a proto3 JSON parser should be
+// able to accept both UTC and other timezones (as indicated by an offset).
+//
+// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
+// 01:30 UTC on January 15, 2017.
+//
+// In JavaScript, one can convert a Date object to this format using the
+// standard
+// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
+// method. In Python, a standard `datetime.datetime` object can be converted
+// to this format using
+// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
+// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
+// the Joda Time's [`ISODateTimeFormat.dateTime()`](
+// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
+// ) to obtain a formatter capable of generating timestamps in this format.
+//
+message Timestamp {
+ // Represents seconds of UTC time since Unix epoch
+ // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
+ // 9999-12-31T23:59:59Z inclusive.
+ int64 seconds = 1;
+
+ // Non-negative fractions of a second at nanosecond resolution. Negative
+ // second values with fractions must still have non-negative nanos values
+ // that count forward in time. Must be from 0 to 999,999,999
+ // inclusive.
+ int32 nanos = 2;
+}
diff --git a/example/main.go b/example/main.go
new file mode 100644
index 0000000..49bace7
--- /dev/null
+++ b/example/main.go
@@ -0,0 +1,9 @@
+package main
+
+import "github.com/begonia-org/go-sdk/example"
+
+func main() {
+ go example.Run("0.0.0.0:1949")
+ example.Run("0.0.0.0:2024")
+
+}
diff --git a/gateway/formdata_test.go b/gateway/formdata_test.go
index f6244d8..64b2c44 100644
--- a/gateway/formdata_test.go
+++ b/gateway/formdata_test.go
@@ -150,6 +150,23 @@ func TestFormUrlEncodedErr(t *testing.T) {
patch.Reset()
}
+ formData := url.Values{}
+ formData.Add("message", "John Doe")
+ formData.Add("allow", api.EnumAllow_DENY.String())
+ req := make(map[string]interface{})
+ decoder := &FormUrlEncodedDecoder{r: strings.NewReader(formData.Encode())}
+ err := decoder.Decode(req)
+ c.So(err, c.ShouldBeNil)
+
+ patch := gomonkey.ApplyFuncReturn(url.ParseQuery, nil, fmt.Errorf("parseQuery error"))
+ defer patch.Reset()
+ req2 := make(map[string]interface{})
+
+ decoder2 := &FormUrlEncodedDecoder{r: strings.NewReader(formData.Encode())}
+ err = decoder2.Decode(req2)
+ c.So(err, c.ShouldNotBeNil)
+ c.So(err.Error(), c.ShouldContainSubstring, "parseQuery error")
+ patch.Reset()
})
}
@@ -270,5 +287,6 @@ func TestFormDataValueErr(t *testing.T) {
c.So(err, c.ShouldNotBeNil)
}
}
+
})
}
diff --git a/gateway/gateway.go b/gateway/gateway.go
index c2e9863..b5b6eca 100644
--- a/gateway/gateway.go
+++ b/gateway/gateway.go
@@ -90,9 +90,9 @@ func (g *GatewayServer) RegisterService(ctx context.Context, pd ProtobufDescript
return g.httpGateway.RegisterHandlerClient(ctx, pd, g.gatewayMux)
}
func (g *GatewayServer) RegisterLocalService(ctx context.Context, pd ProtobufDescription, sd *grpc.ServiceDesc, ss any) error {
- info:=g.grpcServer.GetServiceInfo()
- if _,ok:=info[sd.ServiceName];ok{
- return fmt.Errorf("service %s already exists",sd.ServiceName)
+ info := g.grpcServer.GetServiceInfo()
+ if _, ok := info[sd.ServiceName]; ok {
+ return fmt.Errorf("service %s already exists", sd.ServiceName)
}
g.grpcServer.RegisterService(sd, ss)
return g.httpGateway.RegisterHandlerClient(ctx, pd, g.gatewayMux)
diff --git a/gateway/http_test.go b/gateway/http_test.go
index e812e0f..1ca1c2c 100644
--- a/gateway/http_test.go
+++ b/gateway/http_test.go
@@ -1180,8 +1180,18 @@ func testPanicRecover(t *testing.T) {
patch.Reset()
})
}
+func testHttp2(t *testing.T) {
+ c.Convey("test http2", t, func() {
+ exampleCli := example.NewClient(fmt.Sprintf("127.0.0.1:%d", gwPort))
+ msg, err := exampleCli.SayHello()
+ c.So(err, c.ShouldBeNil)
+ t.Log(msg)
+ c.So(msg, c.ShouldNotBeEmpty)
+ })
+}
func TestHttp(t *testing.T) {
t.Run("testRegisterClient", testRegisterClient)
+ t.Run("testHttp2", testHttp2)
t.Run("testRequestGet", testRequestGet)
t.Run("testPanicRecover", testPanicRecover)
t.Run("testCors", testCors)
diff --git a/gateway/types_test.go b/gateway/types_test.go
new file mode 100644
index 0000000..31c56f0
--- /dev/null
+++ b/gateway/types_test.go
@@ -0,0 +1,30 @@
+package gateway
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/agiledragon/gomonkey/v2"
+ hello "github.com/begonia-org/go-sdk/api/example/v1"
+ c "github.com/smartystreets/goconvey/convey"
+)
+
+func TestClientSideStreamClient(t *testing.T) {
+ c.Convey("test clientSideStreamClient", t, func() {
+ out := &hello.HelloReply{}
+ client := &clientSideStreamClient{ClientStream: &clientStreamMock{}, out: out.ProtoReflect().Descriptor()}
+ patch := gomonkey.ApplyFuncReturn((*clientStreamMock).CloseSend, fmt.Errorf("test"))
+ defer patch.Reset()
+ _, err := client.CloseAndRecv()
+ c.So(err, c.ShouldNotBeNil)
+ c.So(err.Error(), c.ShouldContainSubstring, "test")
+ patch.Reset()
+ patch2 := gomonkey.ApplyFuncReturn((*clientStreamMock).RecvMsg, fmt.Errorf("test recv error"))
+ defer patch2.Reset()
+ _, err = client.CloseAndRecv()
+ c.So(err, c.ShouldNotBeNil)
+ c.So(err.Error(), c.ShouldContainSubstring, "test recv error")
+ patch2.Reset()
+
+ })
+}
diff --git a/gateway/websocket.go b/gateway/websocket.go
index 25254b3..c36502a 100644
--- a/gateway/websocket.go
+++ b/gateway/websocket.go
@@ -22,7 +22,7 @@ type websocketForwarder struct {
http.ResponseWriter
websocket *websocket.Conn
responseType int
- mux sync.Mutex
+ mux sync.Mutex
}
func NewWebsocketForwarder(w http.ResponseWriter, req *http.Request, responseType int) (WebsocketForwarder, error) {
@@ -34,7 +34,7 @@ func NewWebsocketForwarder(w http.ResponseWriter, req *http.Request, responseTyp
if err != nil {
return nil, err
}
- return &websocketForwarder{w, conn, responseType,sync.Mutex{}}, nil
+ return &websocketForwarder{w, conn, responseType, sync.Mutex{}}, nil
}
func (w *websocketForwarder) Flush() {
}
diff --git a/go.mod b/go.mod
index 4839603..f574cc6 100644
--- a/go.mod
+++ b/go.mod
@@ -80,7 +80,7 @@ require (
require (
github.com/agiledragon/gomonkey/v2 v2.11.0
github.com/begonia-org/go-loadbalancer v0.0.0-20240519060752-71ca464f0f1a
- github.com/begonia-org/go-sdk v0.0.0-20240601175127-e9531218a7f3
+ github.com/begonia-org/go-sdk v0.0.0-20240602084009-85eabb12d70e
github.com/go-git/go-git/v5 v5.11.0
github.com/go-playground/validator/v10 v10.19.0
github.com/gorilla/websocket v1.5.0
diff --git a/go.sum b/go.sum
index 5673527..c99676e 100644
--- a/go.sum
+++ b/go.sum
@@ -15,6 +15,7 @@ github.com/agiledragon/gomonkey/v2 v2.11.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoa
github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk=
github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
@@ -24,6 +25,8 @@ github.com/begonia-org/go-loadbalancer v0.0.0-20240519060752-71ca464f0f1a h1:Mpw
github.com/begonia-org/go-loadbalancer v0.0.0-20240519060752-71ca464f0f1a/go.mod h1:crPS67sfgmgv47psftwfmTMbmTfdepVm8MPeqApINlI=
github.com/begonia-org/go-sdk v0.0.0-20240601175127-e9531218a7f3 h1:DLlhzfvYD81+QjEQqcgkKccS0nowjTU6wp/GCsLHT2M=
github.com/begonia-org/go-sdk v0.0.0-20240601175127-e9531218a7f3/go.mod h1:I70a3fiAADGrOoOC3lv408rFcTRhTwLt3pwr6cQwB4Y=
+github.com/begonia-org/go-sdk v0.0.0-20240602084009-85eabb12d70e h1:R7xQlKsiWhWrR7ewCwpkHNYJqs1mXBoiI2+3TXD1qT0=
+github.com/begonia-org/go-sdk v0.0.0-20240602084009-85eabb12d70e/go.mod h1:I70a3fiAADGrOoOC3lv408rFcTRhTwLt3pwr6cQwB4Y=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
@@ -114,6 +117,7 @@ github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7Fsg
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
@@ -154,6 +158,7 @@ github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCy
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -191,6 +196,7 @@ github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0=
github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I=
github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8=
github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
@@ -393,6 +399,7 @@ gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UD
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
diff --git a/testdata/gateway.json b/testdata/gateway.json
index 7959aab..14807a4 100644
--- a/testdata/gateway.json
+++ b/testdata/gateway.json
@@ -1,302 +1,296 @@
{
- "/integration.TestService/Body": [
- {
- "FullMethodName": "/integration.TestService/Body",
- "HttpMethod": "GET",
- "HttpUri": "/test/body",
- "InName": "TestRequest",
- "InPkg": "integration",
- "IsClientStream": false,
- "IsServerStream": false,
- "OutName": "HttpBody",
- "OutPkg": "google.api",
- "PathParams": [],
- "Pattern": {},
- "Pkg": "integration",
- "Template": {
- "Fields": null,
- "OpCodes": [
- 2,
- 0,
- 2,
- 1
- ],
- "Pool": [
- "test",
- "body"
- ],
- "Template": "/test/body",
- "Verb": "",
- "Version": 1
- }
- }
- ],
- "/integration.TestService/Custom": [
- {
- "FullMethodName": "/integration.TestService/Custom",
- "HttpMethod": "GET",
- "HttpUri": "/test/custom",
- "InName": "TestRequest",
- "InPkg": "integration",
- "IsClientStream": false,
- "IsServerStream": false,
- "OutName": "TestRequest",
- "OutPkg": "integration",
- "PathParams": [],
- "Pattern": {},
- "Pkg": "integration",
- "Template": {
- "Fields": null,
- "OpCodes": [
- 2,
- 0,
- 2,
- 1
- ],
- "Pool": [
- "test",
- "custom"
- ],
- "Template": "/test/custom",
- "Verb": "",
- "Version": 1
- },
- "http_response": "begonia.org.sdk.common.HttpResponse"
- }
- ],
- "/integration.TestService/Delete": [
- {
- "FullMethodName": "/integration.TestService/Delete",
- "HttpMethod": "DELETE",
- "HttpUri": "/test/del",
- "InName": "TestRequest",
- "InPkg": "integration",
- "IsClientStream": false,
- "IsServerStream": false,
- "OutName": "TestResponse",
- "OutPkg": "integration",
- "PathParams": [],
- "Pattern": {},
- "Pkg": "integration",
- "Template": {
- "Fields": null,
- "OpCodes": [
- 2,
- 0,
- 2,
- 1
- ],
- "Pool": [
- "test",
- "del"
- ],
- "Template": "/test/del",
- "Verb": "",
- "Version": 1
- },
- "http_response": "begonia.org.sdk.common.HttpResponse"
- }
- ],
- "/integration.TestService/Get": [
- {
- "FullMethodName": "/integration.TestService/Get",
- "HttpMethod": "GET",
- "HttpUri": "/test/get",
- "InName": "TestRequest",
- "InPkg": "integration",
- "IsClientStream": false,
- "IsServerStream": false,
- "OutName": "TestResponse",
- "OutPkg": "integration",
- "PathParams": [],
- "Pattern": {},
- "Pkg": "integration",
- "Template": {
- "Fields": null,
- "OpCodes": [
- 2,
- 0,
- 2,
- 1
- ],
- "Pool": [
- "test",
- "get"
- ],
- "Template": "/test/get",
- "Verb": "",
- "Version": 1
- },
- "http_response": "begonia.org.sdk.common.HttpResponse"
- }
- ],
- "/integration.TestService/Patch": [
- {
- "FullMethodName": "/integration.TestService/Patch",
- "HttpMethod": "PATCH",
- "HttpUri": "/test/patch",
- "InName": "TestRequest",
- "InPkg": "integration",
- "IsClientStream": false,
- "IsServerStream": false,
- "OutName": "TestResponse",
- "OutPkg": "integration",
- "PathParams": [],
- "Pattern": {},
- "Pkg": "integration",
- "Template": {
- "Fields": null,
- "OpCodes": [
- 2,
- 0,
- 2,
- 1
- ],
- "Pool": [
- "test",
- "patch"
- ],
- "Template": "/test/patch",
- "Verb": "",
- "Version": 1
- },
- "http_response": "begonia.org.sdk.common.HttpResponse"
- }
- ],
- "/integration.TestService/Post": [
- {
- "FullMethodName": "/integration.TestService/Post",
- "HttpMethod": "POST",
- "HttpUri": "/test/post",
- "InName": "TestRequest",
- "InPkg": "integration",
- "IsClientStream": false,
- "IsServerStream": false,
- "OutName": "TestResponse",
- "OutPkg": "integration",
- "PathParams": [],
- "Pattern": {},
- "Pkg": "integration",
- "Template": {
- "Fields": null,
- "OpCodes": [
- 2,
- 0,
- 2,
- 1
- ],
- "Pool": [
- "test",
- "post"
- ],
- "Template": "/test/post",
- "Verb": "",
- "Version": 1
- },
- "http_response": "begonia.org.sdk.common.HttpResponse"
- }
- ],
- "/integration.TestService/Put": [
- {
- "FullMethodName": "/integration.TestService/Put",
- "HttpMethod": "PUT",
- "HttpUri": "/test/put",
- "InName": "TestRequest",
- "InPkg": "integration",
- "IsClientStream": false,
- "IsServerStream": false,
- "OutName": "TestResponse",
- "OutPkg": "integration",
- "PathParams": [],
- "Pattern": {},
- "Pkg": "integration",
- "Template": {
- "Fields": null,
- "OpCodes": [
- 2,
- 0,
- 2,
- 1
- ],
- "Pool": [
- "test",
- "put"
- ],
- "Template": "/test/put",
- "Verb": "",
- "Version": 1
- },
- "http_response": "begonia.org.sdk.common.HttpResponse"
- }
- ],
- "/integration.TestServiceWithoutOptions/Get": [
- {
- "FullMethodName": "/integration.TestServiceWithoutOptions/Get",
- "HttpMethod": "GET",
- "HttpUri": "/test/v2/get",
- "InName": "TestRequest",
- "InPkg": "integration",
- "IsClientStream": false,
- "IsServerStream": false,
- "OutName": "TestResponse",
- "OutPkg": "integration",
- "PathParams": [],
- "Pattern": {},
- "Pkg": "integration",
- "Template": {
- "Fields": null,
- "OpCodes": [
- 2,
- 0,
- 2,
- 1,
- 2,
- 2
- ],
- "Pool": [
- "test",
- "v2",
- "get"
- ],
- "Template": "/test/v2/get",
- "Verb": "",
- "Version": 1
- }
- }
- ],
- "/integration.TestServiceWithoutOptions/Post": [
- {
- "FullMethodName": "/integration.TestServiceWithoutOptions/Post",
- "HttpMethod": "POST",
- "HttpUri": "/test/v2/post",
- "InName": "TestRequest",
- "InPkg": "integration",
- "IsClientStream": false,
- "IsServerStream": false,
- "OutName": "TestResponse",
- "OutPkg": "integration",
- "PathParams": [],
- "Pattern": {},
- "Pkg": "integration",
- "Template": {
- "Fields": null,
- "OpCodes": [
- 2,
- 0,
- 2,
- 1,
- 2,
- 2
- ],
- "Pool": [
- "test",
- "v2",
- "post"
- ],
- "Template": "/test/v2/post",
- "Verb": "",
- "Version": 1
- }
- }
- ]
-}
+ "/integration.TestService/Body": [
+ {
+ "Pattern": {},
+ "Template": {
+ "Version": 1,
+ "OpCodes": [
+ 2,
+ 0,
+ 2,
+ 1
+ ],
+ "Pool": [
+ "test",
+ "body"
+ ],
+ "Verb": "",
+ "Fields": null,
+ "Template": "/test/body"
+ },
+ "HttpMethod": "GET",
+ "FullMethodName": "/integration.TestService/Body",
+ "HttpUri": "/test/body",
+ "PathParams": [],
+ "InName": "TestRequest",
+ "OutName": "HttpBody",
+ "IsClientStream": false,
+ "IsServerStream": false,
+ "Pkg": "integration",
+ "InPkg": "integration",
+ "OutPkg": "google.api"
+ }
+ ],
+ "/integration.TestService/Custom": [
+ {
+ "Pattern": {},
+ "Template": {
+ "Version": 1,
+ "OpCodes": [
+ 2,
+ 0,
+ 2,
+ 1
+ ],
+ "Pool": [
+ "test",
+ "custom"
+ ],
+ "Verb": "",
+ "Fields": null,
+ "Template": "/test/custom"
+ },
+ "HttpMethod": "GET",
+ "FullMethodName": "/integration.TestService/Custom",
+ "HttpUri": "/test/custom",
+ "PathParams": [],
+ "InName": "TestRequest",
+ "OutName": "TestRequest",
+ "IsClientStream": false,
+ "IsServerStream": false,
+ "Pkg": "integration",
+ "InPkg": "integration",
+ "OutPkg": "integration"
+ }
+ ],
+ "/integration.TestService/Delete": [
+ {
+ "Pattern": {},
+ "Template": {
+ "Version": 1,
+ "OpCodes": [
+ 2,
+ 0,
+ 2,
+ 1
+ ],
+ "Pool": [
+ "test",
+ "del"
+ ],
+ "Verb": "",
+ "Fields": null,
+ "Template": "/test/del"
+ },
+ "HttpMethod": "DELETE",
+ "FullMethodName": "/integration.TestService/Delete",
+ "HttpUri": "/test/del",
+ "PathParams": [],
+ "InName": "TestRequest",
+ "OutName": "TestResponse",
+ "IsClientStream": false,
+ "IsServerStream": false,
+ "Pkg": "integration",
+ "InPkg": "integration",
+ "OutPkg": "integration"
+ }
+ ],
+ "/integration.TestService/Get": [
+ {
+ "Pattern": {},
+ "Template": {
+ "Version": 1,
+ "OpCodes": [
+ 2,
+ 0,
+ 2,
+ 1
+ ],
+ "Pool": [
+ "test",
+ "get"
+ ],
+ "Verb": "",
+ "Fields": null,
+ "Template": "/test/get"
+ },
+ "HttpMethod": "GET",
+ "FullMethodName": "/integration.TestService/Get",
+ "HttpUri": "/test/get",
+ "PathParams": [],
+ "InName": "TestRequest",
+ "OutName": "TestResponse",
+ "IsClientStream": false,
+ "IsServerStream": false,
+ "Pkg": "integration",
+ "InPkg": "integration",
+ "OutPkg": "integration"
+ }
+ ],
+ "/integration.TestService/Patch": [
+ {
+ "Pattern": {},
+ "Template": {
+ "Version": 1,
+ "OpCodes": [
+ 2,
+ 0,
+ 2,
+ 1
+ ],
+ "Pool": [
+ "test",
+ "patch"
+ ],
+ "Verb": "",
+ "Fields": null,
+ "Template": "/test/patch"
+ },
+ "HttpMethod": "PATCH",
+ "FullMethodName": "/integration.TestService/Patch",
+ "HttpUri": "/test/patch",
+ "PathParams": [],
+ "InName": "TestRequest",
+ "OutName": "TestResponse",
+ "IsClientStream": false,
+ "IsServerStream": false,
+ "Pkg": "integration",
+ "InPkg": "integration",
+ "OutPkg": "integration"
+ }
+ ],
+ "/integration.TestService/Post": [
+ {
+ "Pattern": {},
+ "Template": {
+ "Version": 1,
+ "OpCodes": [
+ 2,
+ 0,
+ 2,
+ 1
+ ],
+ "Pool": [
+ "test",
+ "post"
+ ],
+ "Verb": "",
+ "Fields": null,
+ "Template": "/test/post"
+ },
+ "HttpMethod": "POST",
+ "FullMethodName": "/integration.TestService/Post",
+ "HttpUri": "/test/post",
+ "PathParams": [],
+ "InName": "TestRequest",
+ "OutName": "TestResponse",
+ "IsClientStream": false,
+ "IsServerStream": false,
+ "Pkg": "integration",
+ "InPkg": "integration",
+ "OutPkg": "integration"
+ }
+ ],
+ "/integration.TestService/Put": [
+ {
+ "Pattern": {},
+ "Template": {
+ "Version": 1,
+ "OpCodes": [
+ 2,
+ 0,
+ 2,
+ 1
+ ],
+ "Pool": [
+ "test",
+ "put"
+ ],
+ "Verb": "",
+ "Fields": null,
+ "Template": "/test/put"
+ },
+ "HttpMethod": "PUT",
+ "FullMethodName": "/integration.TestService/Put",
+ "HttpUri": "/test/put",
+ "PathParams": [],
+ "InName": "TestRequest",
+ "OutName": "TestResponse",
+ "IsClientStream": false,
+ "IsServerStream": false,
+ "Pkg": "integration",
+ "InPkg": "integration",
+ "OutPkg": "integration"
+ }
+ ],
+ "/integration.TestServiceWithoutOptions/Get": [
+ {
+ "Pattern": {},
+ "Template": {
+ "Version": 1,
+ "OpCodes": [
+ 2,
+ 0,
+ 2,
+ 1,
+ 2,
+ 2
+ ],
+ "Pool": [
+ "test",
+ "v2",
+ "get"
+ ],
+ "Verb": "",
+ "Fields": null,
+ "Template": "/test/v2/get"
+ },
+ "HttpMethod": "GET",
+ "FullMethodName": "/integration.TestServiceWithoutOptions/Get",
+ "HttpUri": "/test/v2/get",
+ "PathParams": [],
+ "InName": "TestRequest",
+ "OutName": "TestResponse",
+ "IsClientStream": false,
+ "IsServerStream": false,
+ "Pkg": "integration",
+ "InPkg": "integration",
+ "OutPkg": "integration"
+ }
+ ],
+ "/integration.TestServiceWithoutOptions/Post": [
+ {
+ "Pattern": {},
+ "Template": {
+ "Version": 1,
+ "OpCodes": [
+ 2,
+ 0,
+ 2,
+ 1,
+ 2,
+ 2
+ ],
+ "Pool": [
+ "test",
+ "v2",
+ "post"
+ ],
+ "Verb": "",
+ "Fields": null,
+ "Template": "/test/v2/post"
+ },
+ "HttpMethod": "POST",
+ "FullMethodName": "/integration.TestServiceWithoutOptions/Post",
+ "HttpUri": "/test/v2/post",
+ "PathParams": [],
+ "InName": "TestRequest",
+ "OutName": "TestResponse",
+ "IsClientStream": false,
+ "IsServerStream": false,
+ "Pkg": "integration",
+ "InPkg": "integration",
+ "OutPkg": "integration"
+ }
+ ]
+}
\ No newline at end of file