duyong mac 2 月之前
父節點
當前提交
3ab87c045b

+ 1 - 1
.gitignore

@@ -23,4 +23,4 @@ _testmain.go
 *.exe
 *.test
 *.prof
-
+.idea

+ 46 - 0
dyrpc/client/client.go

@@ -0,0 +1,46 @@
+package main
+
+import (
+	"context"
+	"dy-test/dyrpc/helper"
+	"dy-test/dyrpc/services/prod"
+	"fmt"
+	"google.golang.org/grpc"
+	"log"
+)
+
+const (
+	certFile = "/Users/duyong/workspace/gotest/dyrpc/ssl/client/client.pem"
+	keyFile  = "/Users/duyong/workspace/gotest/dyrpc/ssl/client/client.key"
+	caFile   = "/Users/duyong/workspace/gotest/dyrpc/ssl/ca/ca.pem"
+)
+
+func main() {
+
+	//creds, err := credentials.NewClientTLSFromFile("/Users/duyong/workspace/gotest/dyrpc/ssl/server/server.pem", "localhost")
+	//if err != nil {
+	//	grpclog.Fatalf("Failed to create TLS credentials %v", err)
+	//}
+
+	conn, err := grpc.Dial(":8081", grpc.WithTransportCredentials(helper.GetCredentials(certFile, keyFile, caFile)))
+	if err != nil {
+		log.Fatalf("failed to dial: %v", err)
+	}
+	defer conn.Close()
+
+	client := prod.NewProdServiceClient(conn)
+	res, err := client.GetProdStock(context.Background(), &prod.ProdRequest{ProdId: 100})
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(res.ProdStock)
+
+	prodList, err := client.GetProdStocks(context.Background(), &prod.QueryProdStocks{
+		PageNo:   1,
+		PageSize: 10,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(prodList.ProdRes)
+}

+ 38 - 0
dyrpc/helper/cert_helper.go

@@ -0,0 +1,38 @@
+package helper
+
+import (
+	"crypto/tls"
+	"crypto/x509"
+	"google.golang.org/grpc/credentials"
+	"os"
+)
+
+func GetCredentials(certFile, keyFile, caFile string) credentials.TransportCredentials {
+	// 证书认证-双向认证
+	// 从证书相关文件中读取和解析信息,得到证书公钥、密钥对
+	cert, err := tls.LoadX509KeyPair(certFile,
+		keyFile)
+	if err != nil {
+		panic(err)
+	}
+	// 创建一个新的、空的 CertPool
+	certPool := x509.NewCertPool()
+	ca, err := os.ReadFile(caFile)
+	if err != nil {
+		panic(err)
+	}
+
+	//注意这里只能解析pem类型的根证书,所以需要的是ca.pem
+	// 尝试解析所传入的 PEM 编码的证书。如果解析成功会将其加到 CertPool 中,便于后面的使用
+	certPool.AppendCertsFromPEM(ca)
+
+	// 构建基于 TLS 的 TransportCredentials 选项
+	creds := credentials.NewTLS(&tls.Config{
+		// 设置证书链,允许包含一个或多个
+		Certificates: []tls.Certificate{cert},
+		ServerName:   "localhost", //注意这里的参数为配置文件中所允许的ServerName,也就是其中配置的DNS...
+		RootCAs:      certPool,
+	})
+
+	return creds
+}

+ 35 - 0
dyrpc/httpserver/main.go

@@ -0,0 +1,35 @@
+package main
+
+import (
+	"context"
+	"dy-test/dyrpc/helper"
+	"dy-test/dyrpc/services/prod"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+	"google.golang.org/grpc"
+	"log"
+	"net/http"
+)
+
+const (
+	certFile = "/Users/duyong/workspace/gotest/dyrpc/ssl/client/client.pem"
+	keyFile  = "/Users/duyong/workspace/gotest/dyrpc/ssl/client/client.key"
+	caFile   = "/Users/duyong/workspace/gotest/dyrpc/ssl/ca/ca.pem"
+)
+
+func main() {
+	gwmux := runtime.NewServeMux()
+	opt := []grpc.DialOption{grpc.WithTransportCredentials(helper.GetCredentials(certFile, keyFile, caFile))}
+	err := prod.RegisterProdServiceHandlerFromEndpoint(context.Background(), gwmux, "localhost:8081", opt)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	httpServer := &http.Server{
+		Addr:    ":8080",
+		Handler: gwmux,
+	}
+	err = httpServer.ListenAndServe()
+	if err != nil {
+		log.Fatal(err)
+	}
+}

+ 5 - 0
dyrpc/prod.sh

@@ -0,0 +1,5 @@
+#!/bin/bash
+
+cd ./proto
+protoc --go_out=../services --go-grpc_out=../services   prod.proto
+cd ..

+ 31 - 0
dyrpc/proto/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;
+}

+ 379 - 0
dyrpc/proto/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&param=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;
+}

+ 81 - 0
dyrpc/proto/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;
+}

+ 43 - 0
dyrpc/proto/prod.proto

@@ -0,0 +1,43 @@
+syntax="proto3";
+package  services;
+
+option go_package = "/prod";
+
+import "google/api/annotations.proto";
+
+enum ProdArea{
+  A=0;
+  B=1;
+  C=2;
+}
+
+message ProdRequest {
+  int32 prod_id = 1;
+  ProdArea prod_area = 2;
+}
+
+message ProdResponse {
+  int32 prod_stock = 1;
+}
+
+message QueryProdStocks {
+  int32  pageNo = 1;
+  int32  pageSize = 2;
+}
+
+message ProdStockList {
+  repeated ProdResponse prodRes = 1;
+}
+
+service ProdService {
+  rpc GetProdStock(ProdRequest) returns (ProdResponse){
+    option (google.api.http) = {
+      get: "/v1/prod/{prod_id}"
+    };
+  }
+
+  rpc GetProdStocks(QueryProdStocks)returns(ProdStockList){
+
+  }
+}
+

+ 24 - 0
dyrpc/proto语法.md

@@ -0,0 +1,24 @@
+# 语法使用
+
+## repeated 修饰符 描述数组
+
+```protobuf
+syntax="proto3";
+
+message ProdResponse {
+    int32 prod_stock = 1;
+}
+
+message ProdStockList {
+  repeated ProdResponse prodRes = 1;
+}
+```
+
+
+## 枚举
+
+```protobuf
+
+```
+
+

+ 76 - 0
dyrpc/readme.md

@@ -0,0 +1,76 @@
+# grpc-go
+go的gRPC框架 https://github.com/grpc/grpc-go   
+
+# protobuf 
+protobuf协议编译器
+https://github.com/golang/protobuf  
+##  golang 编译器插件
+
+对于Golang来说,称为protoc-gen-go。
+
+不过在这儿有个小小的坑,github.com/golang/protobuf/protoc-gen-go和google.golang.org/protobuf/cmd/protoc-gen-go是不同的。
+
+区别在于前者是旧版本,后者是google接管后的新版本,他们之间的API是不同的,也就是说用于生成的命令,以及生成的文件都是不一样的。
+
+因为目前的gRPC-go源码中的example用的是后者的生成方式,为了与时俱进,本文也采取最新的方式。
+
+你需要安装两个库:
+
+```bash
+go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
+go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
+```
+
+在网上的一些教程中,有这样的生成方式:
+
+`protoc --go_out=plugins=grpc:. helloworld.proto`
+
+这种生成方式,使用的就是github版本的protoc-gen-go,而目前这个项目已经由Google接管了。
+
+并且,如果使用这种生成方式的话,并不会生成上图中的xxx_grpc.pb.go与xxx.pb.go两个文件,只会生成xxx.pb.go这种文件。
+
+此外,你也可能遇到这种错误:
+
+```bash
+protoc-gen-go-grpc: program not found or is not executable
+Please specify a program using absolute path or make sure the program is available in your PATH system variable
+--go-grpc_out: protoc-gen-go-grpc: Plugin failed with status code 1.
+```
+
+这是因为你没有安装protoc-gen-go-grpc这个插件,这个问题在本文中应该不会出现。
+
+你还可能会遇到这种问题:
+
+```bash
+--go_out: protoc-gen-go: plugins are not supported; use 'protoc --go-grpc_out=...' to generate gRPC
+```
+这是因为你安装的是更新版本的protoc-gen-go,但是你却用了旧版本的生成命令。
+
+但是这两种方法都是可以完成目标的,只不过api不太一样。本文是基于Google版本的protoc-gen-go进行示范。
+
+至于其他更详细的资料,你可以在这里看到:https://github.com/protocolbuffers/protobuf-go/releases/tag/v1.20.0#v1.20-generated-code
+
+## protobuf 协议文档
+
+protobuf 协议文档
+https://protobuf.dev/getting-started/gotutorial 
+
+
+## 使用到的命令
+
+`protoc --go_out=../services --go-grpc_out=../services   prod.proto`
+
+
+
+# grpc-gateway
+
+```bash
+go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
+go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest
+go install google.golang.org/protobuf/cmd/protoc-gen-go@latest 
+go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
+```
+
+```bash
+protoc -I . --grpc-gateway_out ../services prod.proto
+```

+ 53 - 0
dyrpc/server/main.go

@@ -0,0 +1,53 @@
+package main
+
+import (
+	"dy-test/dyrpc/helper"
+	"dy-test/dyrpc/services"
+	"dy-test/dyrpc/services/prod"
+	"google.golang.org/grpc"
+	"net"
+)
+
+const (
+	certFile = "/Users/duyong/workspace/gotest/dyrpc/ssl/server/server.pem"
+	keyFile  = "/Users/duyong/workspace/gotest/dyrpc/ssl/server/server.key"
+	caFile   = "/Users/duyong/workspace/gotest/dyrpc/ssl/ca/ca.pem"
+)
+
+func main() {
+
+	//配置 TLS认证相关文件
+	//creds, err := credentials.NewServerTLSFromFile("/Users/duyong/workspace/gotest/dyrpc/ssl/server/server.pem",
+	//	"/Users/duyong/workspace/gotest/dyrpc/ssl/server/server.key")
+	//if err != nil {
+	//	panic(err)
+	//}
+
+	rpcServer := grpc.NewServer(grpc.Creds(helper.GetCredentials(certFile, keyFile, caFile)))
+	prod.RegisterProdServiceServer(rpcServer, new(services.ProdService))
+
+	listen, err := net.Listen("tcp", ":8081")
+	if err != nil {
+		panic(err)
+	}
+	err = rpcServer.Serve(listen)
+	if err != nil {
+		panic(err)
+	}
+
+	// 让rpc提供http服务
+	//mux := http.NewServeMux()
+	//mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
+	//	fmt.Println(request.Proto)
+	//	fmt.Println(request.Header)
+	//	rpcServer.ServeHTTP(writer, request)
+	//})
+	//
+	//httpServer := &http.Server{
+	//	Addr:    ":8081",
+	//	Handler: mux,
+	//}
+	//
+	//httpServer.ListenAndServeTLS("/Users/duyong/workspace/gotest/dyrpc/ssl/server/server.pem", "/Users/duyong/workspace/gotest/dyrpc/ssl/server/server.key")
+
+}

+ 426 - 0
dyrpc/services/prod/prod.pb.go

@@ -0,0 +1,426 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.34.0
+// 	protoc        v5.26.1
+// source: prod.proto
+
+package prod
+
+import (
+	_ "google.golang.org/genproto/googleapis/api/annotations"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ProdArea int32
+
+const (
+	ProdArea_A ProdArea = 0
+	ProdArea_B ProdArea = 1
+	ProdArea_C ProdArea = 2
+)
+
+// Enum value maps for ProdArea.
+var (
+	ProdArea_name = map[int32]string{
+		0: "A",
+		1: "B",
+		2: "C",
+	}
+	ProdArea_value = map[string]int32{
+		"A": 0,
+		"B": 1,
+		"C": 2,
+	}
+)
+
+func (x ProdArea) Enum() *ProdArea {
+	p := new(ProdArea)
+	*p = x
+	return p
+}
+
+func (x ProdArea) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ProdArea) Descriptor() protoreflect.EnumDescriptor {
+	return file_prod_proto_enumTypes[0].Descriptor()
+}
+
+func (ProdArea) Type() protoreflect.EnumType {
+	return &file_prod_proto_enumTypes[0]
+}
+
+func (x ProdArea) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ProdArea.Descriptor instead.
+func (ProdArea) EnumDescriptor() ([]byte, []int) {
+	return file_prod_proto_rawDescGZIP(), []int{0}
+}
+
+type ProdRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	ProdId   int32    `protobuf:"varint,1,opt,name=prod_id,json=prodId,proto3" json:"prod_id,omitempty"`
+	ProdArea ProdArea `protobuf:"varint,2,opt,name=prod_area,json=prodArea,proto3,enum=services.ProdArea" json:"prod_area,omitempty"`
+}
+
+func (x *ProdRequest) Reset() {
+	*x = ProdRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_prod_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ProdRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProdRequest) ProtoMessage() {}
+
+func (x *ProdRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_prod_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ProdRequest.ProtoReflect.Descriptor instead.
+func (*ProdRequest) Descriptor() ([]byte, []int) {
+	return file_prod_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ProdRequest) GetProdId() int32 {
+	if x != nil {
+		return x.ProdId
+	}
+	return 0
+}
+
+func (x *ProdRequest) GetProdArea() ProdArea {
+	if x != nil {
+		return x.ProdArea
+	}
+	return ProdArea_A
+}
+
+type ProdResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	ProdStock int32 `protobuf:"varint,1,opt,name=prod_stock,json=prodStock,proto3" json:"prod_stock,omitempty"`
+}
+
+func (x *ProdResponse) Reset() {
+	*x = ProdResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_prod_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ProdResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProdResponse) ProtoMessage() {}
+
+func (x *ProdResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_prod_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ProdResponse.ProtoReflect.Descriptor instead.
+func (*ProdResponse) Descriptor() ([]byte, []int) {
+	return file_prod_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ProdResponse) GetProdStock() int32 {
+	if x != nil {
+		return x.ProdStock
+	}
+	return 0
+}
+
+type QueryProdStocks struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	PageNo   int32 `protobuf:"varint,1,opt,name=pageNo,proto3" json:"pageNo,omitempty"`
+	PageSize int32 `protobuf:"varint,2,opt,name=pageSize,proto3" json:"pageSize,omitempty"`
+}
+
+func (x *QueryProdStocks) Reset() {
+	*x = QueryProdStocks{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_prod_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *QueryProdStocks) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*QueryProdStocks) ProtoMessage() {}
+
+func (x *QueryProdStocks) ProtoReflect() protoreflect.Message {
+	mi := &file_prod_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use QueryProdStocks.ProtoReflect.Descriptor instead.
+func (*QueryProdStocks) Descriptor() ([]byte, []int) {
+	return file_prod_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *QueryProdStocks) GetPageNo() int32 {
+	if x != nil {
+		return x.PageNo
+	}
+	return 0
+}
+
+func (x *QueryProdStocks) GetPageSize() int32 {
+	if x != nil {
+		return x.PageSize
+	}
+	return 0
+}
+
+type ProdStockList struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	ProdRes []*ProdResponse `protobuf:"bytes,1,rep,name=prodRes,proto3" json:"prodRes,omitempty"`
+}
+
+func (x *ProdStockList) Reset() {
+	*x = ProdStockList{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_prod_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ProdStockList) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ProdStockList) ProtoMessage() {}
+
+func (x *ProdStockList) ProtoReflect() protoreflect.Message {
+	mi := &file_prod_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ProdStockList.ProtoReflect.Descriptor instead.
+func (*ProdStockList) Descriptor() ([]byte, []int) {
+	return file_prod_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ProdStockList) GetProdRes() []*ProdResponse {
+	if x != nil {
+		return x.ProdRes
+	}
+	return nil
+}
+
+var File_prod_proto protoreflect.FileDescriptor
+
+var file_prod_proto_rawDesc = []byte{
+	0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x73, 0x65,
+	0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61,
+	0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x22, 0x57, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x64, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x09,
+	0x70, 0x72, 0x6f, 0x64, 0x5f, 0x61, 0x72, 0x65, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x41,
+	0x72, 0x65, 0x61, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x64, 0x41, 0x72, 0x65, 0x61, 0x22, 0x2d, 0x0a,
+	0x0c, 0x50, 0x72, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a,
+	0x0a, 0x70, 0x72, 0x6f, 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x05, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x22, 0x45, 0x0a, 0x0f,
+	0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x73, 0x12,
+	0x16, 0x0a, 0x06, 0x70, 0x61, 0x67, 0x65, 0x4e, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
+	0x06, 0x70, 0x61, 0x67, 0x65, 0x4e, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53,
+	0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53,
+	0x69, 0x7a, 0x65, 0x22, 0x41, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x64, 0x53, 0x74, 0x6f, 0x63, 0x6b,
+	0x4c, 0x69, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x18,
+	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
+	0x2e, 0x50, 0x72, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x70,
+	0x72, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x2a, 0x1f, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x64, 0x41, 0x72,
+	0x65, 0x61, 0x12, 0x05, 0x0a, 0x01, 0x41, 0x10, 0x00, 0x12, 0x05, 0x0a, 0x01, 0x42, 0x10, 0x01,
+	0x12, 0x05, 0x0a, 0x01, 0x43, 0x10, 0x02, 0x32, 0xaf, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x64,
+	0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x59, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x50, 0x72,
+	0x6f, 0x64, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x12, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+	0x65, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
+	0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12,
+	0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x64, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x64, 0x5f, 0x69,
+	0x64, 0x7d, 0x12, 0x45, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x64, 0x53, 0x74, 0x6f,
+	0x63, 0x6b, 0x73, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x51,
+	0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x73, 0x1a, 0x17,
+	0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x53, 0x74,
+	0x6f, 0x63, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x42, 0x07, 0x5a, 0x05, 0x2f, 0x70, 0x72,
+	0x6f, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_prod_proto_rawDescOnce sync.Once
+	file_prod_proto_rawDescData = file_prod_proto_rawDesc
+)
+
+func file_prod_proto_rawDescGZIP() []byte {
+	file_prod_proto_rawDescOnce.Do(func() {
+		file_prod_proto_rawDescData = protoimpl.X.CompressGZIP(file_prod_proto_rawDescData)
+	})
+	return file_prod_proto_rawDescData
+}
+
+var file_prod_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_prod_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_prod_proto_goTypes = []interface{}{
+	(ProdArea)(0),           // 0: services.ProdArea
+	(*ProdRequest)(nil),     // 1: services.ProdRequest
+	(*ProdResponse)(nil),    // 2: services.ProdResponse
+	(*QueryProdStocks)(nil), // 3: services.QueryProdStocks
+	(*ProdStockList)(nil),   // 4: services.ProdStockList
+}
+var file_prod_proto_depIdxs = []int32{
+	0, // 0: services.ProdRequest.prod_area:type_name -> services.ProdArea
+	2, // 1: services.ProdStockList.prodRes:type_name -> services.ProdResponse
+	1, // 2: services.ProdService.GetProdStock:input_type -> services.ProdRequest
+	3, // 3: services.ProdService.GetProdStocks:input_type -> services.QueryProdStocks
+	2, // 4: services.ProdService.GetProdStock:output_type -> services.ProdResponse
+	4, // 5: services.ProdService.GetProdStocks:output_type -> services.ProdStockList
+	4, // [4:6] is the sub-list for method output_type
+	2, // [2:4] is the sub-list for method input_type
+	2, // [2:2] is the sub-list for extension type_name
+	2, // [2:2] is the sub-list for extension extendee
+	0, // [0:2] is the sub-list for field type_name
+}
+
+func init() { file_prod_proto_init() }
+func file_prod_proto_init() {
+	if File_prod_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_prod_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ProdRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_prod_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ProdResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_prod_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*QueryProdStocks); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_prod_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ProdStockList); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_prod_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   4,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_prod_proto_goTypes,
+		DependencyIndexes: file_prod_proto_depIdxs,
+		EnumInfos:         file_prod_proto_enumTypes,
+		MessageInfos:      file_prod_proto_msgTypes,
+	}.Build()
+	File_prod_proto = out.File
+	file_prod_proto_rawDesc = nil
+	file_prod_proto_goTypes = nil
+	file_prod_proto_depIdxs = nil
+}

+ 189 - 0
dyrpc/services/prod/prod.pb.gw.go

@@ -0,0 +1,189 @@
+// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
+// source: prod.proto
+
+/*
+Package prod is a reverse proxy.
+
+It translates gRPC into RESTful JSON APIs.
+*/
+package prod
+
+import (
+	"context"
+	"io"
+	"net/http"
+
+	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+	"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/grpclog"
+	"google.golang.org/grpc/metadata"
+	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/proto"
+)
+
+// Suppress "imported and not used" errors
+var _ codes.Code
+var _ io.Reader
+var _ status.Status
+var _ = runtime.String
+var _ = utilities.NewDoubleArray
+var _ = metadata.Join
+
+func request_ProdService_GetProdStock_0(ctx context.Context, marshaler runtime.Marshaler, client ProdServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq ProdRequest
+	var metadata runtime.ServerMetadata
+
+	var (
+		val string
+		ok  bool
+		err error
+		_   = err
+	)
+
+	val, ok = pathParams["prod_id"]
+	if !ok {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "prod_id")
+	}
+
+	protoReq.ProdId, err = runtime.Int32(val)
+	if err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "prod_id", err)
+	}
+
+	msg, err := client.GetProdStock(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func local_request_ProdService_GetProdStock_0(ctx context.Context, marshaler runtime.Marshaler, server ProdServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq ProdRequest
+	var metadata runtime.ServerMetadata
+
+	var (
+		val string
+		ok  bool
+		err error
+		_   = err
+	)
+
+	val, ok = pathParams["prod_id"]
+	if !ok {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "prod_id")
+	}
+
+	protoReq.ProdId, err = runtime.Int32(val)
+	if err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "prod_id", err)
+	}
+
+	msg, err := server.GetProdStock(ctx, &protoReq)
+	return msg, metadata, err
+
+}
+
+// RegisterProdServiceHandlerServer registers the http handlers for service ProdService to "mux".
+// UnaryRPC     :call ProdServiceServer directly.
+// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
+// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterProdServiceHandlerFromEndpoint instead.
+func RegisterProdServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ProdServiceServer) error {
+
+	mux.Handle("GET", pattern_ProdService_GetProdStock_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		var stream runtime.ServerTransportStream
+		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		var err error
+		var annotatedContext context.Context
+		annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/services.ProdService/GetProdStock", runtime.WithHTTPPathPattern("/v1/prod/{prod_id}"))
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := local_request_ProdService_GetProdStock_0(annotatedContext, inboundMarshaler, server, req, pathParams)
+		md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+		annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+		if err != nil {
+			runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_ProdService_GetProdStock_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	return nil
+}
+
+// RegisterProdServiceHandlerFromEndpoint is same as RegisterProdServiceHandler but
+// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
+func RegisterProdServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
+	conn, err := grpc.DialContext(ctx, endpoint, opts...)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if err != nil {
+			if cerr := conn.Close(); cerr != nil {
+				grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+			}
+			return
+		}
+		go func() {
+			<-ctx.Done()
+			if cerr := conn.Close(); cerr != nil {
+				grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+			}
+		}()
+	}()
+
+	return RegisterProdServiceHandler(ctx, mux, conn)
+}
+
+// RegisterProdServiceHandler registers the http handlers for service ProdService to "mux".
+// The handlers forward requests to the grpc endpoint over "conn".
+func RegisterProdServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
+	return RegisterProdServiceHandlerClient(ctx, mux, NewProdServiceClient(conn))
+}
+
+// RegisterProdServiceHandlerClient registers the http handlers for service ProdService
+// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ProdServiceClient".
+// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ProdServiceClient"
+// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
+// "ProdServiceClient" to call the correct interceptors.
+func RegisterProdServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ProdServiceClient) error {
+
+	mux.Handle("GET", pattern_ProdService_GetProdStock_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		var err error
+		var annotatedContext context.Context
+		annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/services.ProdService/GetProdStock", runtime.WithHTTPPathPattern("/v1/prod/{prod_id}"))
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_ProdService_GetProdStock_0(annotatedContext, inboundMarshaler, client, req, pathParams)
+		annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+		if err != nil {
+			runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_ProdService_GetProdStock_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
+	return nil
+}
+
+var (
+	pattern_ProdService_GetProdStock_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "prod", "prod_id"}, ""))
+)
+
+var (
+	forward_ProdService_GetProdStock_0 = runtime.ForwardResponseMessage
+)

+ 146 - 0
dyrpc/services/prod/prod_grpc.pb.go

@@ -0,0 +1,146 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.3.0
+// - protoc             v5.26.1
+// source: prod.proto
+
+package prod
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+const (
+	ProdService_GetProdStock_FullMethodName  = "/services.ProdService/GetProdStock"
+	ProdService_GetProdStocks_FullMethodName = "/services.ProdService/GetProdStocks"
+)
+
+// ProdServiceClient is the client API for ProdService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type ProdServiceClient interface {
+	GetProdStock(ctx context.Context, in *ProdRequest, opts ...grpc.CallOption) (*ProdResponse, error)
+	GetProdStocks(ctx context.Context, in *QueryProdStocks, opts ...grpc.CallOption) (*ProdStockList, error)
+}
+
+type prodServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewProdServiceClient(cc grpc.ClientConnInterface) ProdServiceClient {
+	return &prodServiceClient{cc}
+}
+
+func (c *prodServiceClient) GetProdStock(ctx context.Context, in *ProdRequest, opts ...grpc.CallOption) (*ProdResponse, error) {
+	out := new(ProdResponse)
+	err := c.cc.Invoke(ctx, ProdService_GetProdStock_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *prodServiceClient) GetProdStocks(ctx context.Context, in *QueryProdStocks, opts ...grpc.CallOption) (*ProdStockList, error) {
+	out := new(ProdStockList)
+	err := c.cc.Invoke(ctx, ProdService_GetProdStocks_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// ProdServiceServer is the server API for ProdService service.
+// All implementations must embed UnimplementedProdServiceServer
+// for forward compatibility
+type ProdServiceServer interface {
+	GetProdStock(context.Context, *ProdRequest) (*ProdResponse, error)
+	GetProdStocks(context.Context, *QueryProdStocks) (*ProdStockList, error)
+	mustEmbedUnimplementedProdServiceServer()
+}
+
+// UnimplementedProdServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedProdServiceServer struct {
+}
+
+func (UnimplementedProdServiceServer) GetProdStock(context.Context, *ProdRequest) (*ProdResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetProdStock not implemented")
+}
+func (UnimplementedProdServiceServer) GetProdStocks(context.Context, *QueryProdStocks) (*ProdStockList, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetProdStocks not implemented")
+}
+func (UnimplementedProdServiceServer) mustEmbedUnimplementedProdServiceServer() {}
+
+// UnsafeProdServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to ProdServiceServer will
+// result in compilation errors.
+type UnsafeProdServiceServer interface {
+	mustEmbedUnimplementedProdServiceServer()
+}
+
+func RegisterProdServiceServer(s grpc.ServiceRegistrar, srv ProdServiceServer) {
+	s.RegisterService(&ProdService_ServiceDesc, srv)
+}
+
+func _ProdService_GetProdStock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ProdRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProdServiceServer).GetProdStock(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: ProdService_GetProdStock_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProdServiceServer).GetProdStock(ctx, req.(*ProdRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _ProdService_GetProdStocks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(QueryProdStocks)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ProdServiceServer).GetProdStocks(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: ProdService_GetProdStocks_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ProdServiceServer).GetProdStocks(ctx, req.(*QueryProdStocks))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// ProdService_ServiceDesc is the grpc.ServiceDesc for ProdService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var ProdService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "services.ProdService",
+	HandlerType: (*ProdServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "GetProdStock",
+			Handler:    _ProdService_GetProdStock_Handler,
+		},
+		{
+			MethodName: "GetProdStocks",
+			Handler:    _ProdService_GetProdStocks_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "prod.proto",
+}

+ 28 - 0
dyrpc/services/prod_service.go

@@ -0,0 +1,28 @@
+package services
+
+import (
+	"context"
+	"dy-test/dyrpc/services/prod"
+)
+
+type ProdService struct {
+	prod.UnimplementedProdServiceServer
+}
+
+func (p *ProdService) GetProdStock(ctx context.Context, request *prod.ProdRequest) (*prod.ProdResponse, error) {
+	return &prod.ProdResponse{ProdStock: 20}, nil
+}
+
+func (p *ProdService) GetProdStocks(context.Context, *prod.QueryProdStocks) (*prod.ProdStockList, error) {
+	prdRes := []*prod.ProdResponse{
+
+		&prod.ProdResponse{ProdStock: 10},
+		&prod.ProdResponse{ProdStock: 20},
+		&prod.ProdResponse{ProdStock: 30},
+	}
+	return &prod.ProdStockList{ProdRes: prdRes}, nil
+}
+
+func (p *ProdService) mustEmbedUnimplementedProdServiceServer() {
+
+}

+ 1 - 0
dyrpc/ssl/.srl

@@ -0,0 +1 @@
+9CFA264961A1BF57

+ 27 - 0
dyrpc/ssl/ca/ca.csr

@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIEmDCCAoACAQAwUzELMAkGA1UEBhMCQ04xDzANBgNVBAgMBlNoYW5YaTEQMA4G
+A1UEBwwHVGFpWXVhbjENMAsGA1UECgwEU3RlcDESMBAGA1UEAwwJbG9jYWxob3N0
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxoKjkq0VBFhBXA8Qu6K/
+wpfqReGeGOLxaJmldmvHzYpVwZXadnlmQCVw8T6StS705VDvwbVimZdp41xeA/4U
+i+OQZXbSFnlDwW6+e2XdMKFYOXIBaLSbyX+IEVRQqbOfI7beaR16iJTKjj0Zs+/d
+sUUJm8Ov8jqeMgY2dI7iz+ahx9r6tqRDde9oj75pFhXn8lLbTLiq694z9PlyIHGU
+/7ek4VETu5Osjuz+inb++QZYoVJ8NV4sD/2VYeS6imznZVwZ7tDpyfjxkzDg1cl0
+Gx043gHilv1bI+Ofpb4tLfys4ISuXELC5+xiQY9Px5Zr51xyYq1e3dUXl/J9hW7x
+bGmquoUB2AcNtvkRXYRMSP7qsfjswtB4FuWdpkpRrhJHdGpRvYPYQ7bsEfCfBgZN
+jNUSsFW9Pgd/nNavSvuJyCpZei6msvE9FbYqyZ8HsPACcm9JVjF8nGJ5PBOvXozC
+sDFi0Bti+dUCkk/HLk18wLXuSQdHwpSEoTbRv0rOhKrxZ4FMS/9aYR1z5N0hM5RJ
+G7YgGA6X/+t2VW0TG1ER+LM4803b4XQmPbUdfTdl1Dzaf3DjV+RGGi1Ot+ln/T3m
+OQvUCy9q4ntDqjhcJiE2vpiM6mQeEfonaLXO/FvHVdUlnhGX7yuv/bSkPnf5PSiQ
+8aK/PLtVTZ+nGRhvCQbN26cCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4ICAQBc1vDf
+jqyqjPSEdZEFsCoaJ3h7DssMMk+Zo0fh0pYIRrNbcYaBomREQuWv3WGpY0R3A0VN
+gC0Gfr4sjueEMXxP22ndLb+c+/2jYxiEqxT5dUcaGXphCGyc2lihuq0pJjLyGVzM
+96LqAdSFV3ZjFNOBibbyLdtGBtUT6bPHDqJl/rhJEPN9RSZToaIAhguf/w1kHLHQ
+3A6QenAXRqYCR6yO7m1U+0hwUpEOkQ83CFeWsvTPORVP8O6wI9PFYNccNYVveVJY
+EA1wvtaisiDCIDPzfq3seTI17O1/x1dMcoWbKSO+XFh+NeC07htEXY089vXBR+6s
+4SCcQ2VOE7WdXmnKEHStrshFjaR0txDYTUdEs78dKq92SVk8XTpRlos3Uw7JIKu9
+hdVRf+Q7pSj3PF0YYvAAJ6psD00CBwBbgN8PdPFsNwNtBC3Yjsk2/AKSZjY+S6rD
+FwGzbqPGXx388bD0+UaUYBaxX+IqznHkY9Mwt2z6ij3fsFt1zQyK/sAfwp5J5Wdp
+WKauIIkczH0ydMhE9nfZSj7SddJ6NdCuEzenh3AYUKul2phVW9e8zDK9zKcUIJ7+
+Z46f3rLsL5nXqS0j0PQy+NBYdnGoKpTu7SP+aSf8VlsK/flSVvyskzEcogq6h+Jc
+dIqXIUfDwKvWKjDkmCMVqhVU/0Q+jDGv7gsfIg==
+-----END CERTIFICATE REQUEST-----

+ 51 - 0
dyrpc/ssl/ca/ca.key

@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----

+ 30 - 0
dyrpc/ssl/ca/ca.pem

@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFIjCCAwoCCQDeSbcNmEFlTDANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJD
+TjEPMA0GA1UECAwGU2hhblhpMRAwDgYDVQQHDAdUYWlZdWFuMQ0wCwYDVQQKDART
+dGVwMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjQwNTA2MDIxODQ0WhcNMzQwNTA0
+MDIxODQ0WjBTMQswCQYDVQQGEwJDTjEPMA0GA1UECAwGU2hhblhpMRAwDgYDVQQH
+DAdUYWlZdWFuMQ0wCwYDVQQKDARTdGVwMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGgqOSrRUEWEFcDxC7or/Cl+pF
+4Z4Y4vFomaV2a8fNilXBldp2eWZAJXDxPpK1LvTlUO/BtWKZl2njXF4D/hSL45Bl
+dtIWeUPBbr57Zd0woVg5cgFotJvJf4gRVFCps58jtt5pHXqIlMqOPRmz792xRQmb
+w6/yOp4yBjZ0juLP5qHH2vq2pEN172iPvmkWFefyUttMuKrr3jP0+XIgcZT/t6Th
+URO7k6yO7P6Kdv75BlihUnw1XiwP/ZVh5LqKbOdlXBnu0OnJ+PGTMODVyXQbHTje
+AeKW/Vsj45+lvi0t/KzghK5cQsLn7GJBj0/HlmvnXHJirV7d1ReX8n2FbvFsaaq6
+hQHYBw22+RFdhExI/uqx+OzC0HgW5Z2mSlGuEkd0alG9g9hDtuwR8J8GBk2M1RKw
+Vb0+B3+c1q9K+4nIKll6Lqay8T0VtirJnwew8AJyb0lWMXycYnk8E69ejMKwMWLQ
+G2L51QKST8cuTXzAte5JB0fClIShNtG/Ss6EqvFngUxL/1phHXPk3SEzlEkbtiAY
+Dpf/63ZVbRMbURH4szjzTdvhdCY9tR19N2XUPNp/cONX5EYaLU636Wf9PeY5C9QL
+L2rie0OqOFwmITa+mIzqZB4R+idotc78W8dV1SWeEZfvK6/9tKQ+d/k9KJDxor88
+u1VNn6cZGG8JBs3bpwIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQCoQoc2Vk1fu1EX
+OHF7QFov7IIfIt/ubpcVBSNJCShxEUyfNJ8HKs/gA4ehgBj3u02wtK5rOCdJYHab
+0jEwjkJLz8SBzUclpgH6vbYADvKI9cLkJnR5PebO3ap3tMsK0n8KbnTR+TE7YqK3
+VZjynq/swVBeaDtueF1C1WMumrnoiGJxNYiEOknkINK3ae0TE32sXQ4Ptg9OLtLz
+LctrFVi5feVEkkvJ2jAQT1UHq7yRfjCwS2cevK9YWZMOeWhjmMn6eQ6ZSCohOVE0
+AP/uX/8LmLpb1V3pZTGS5DOr0IsfpRE2Zt4SvAafErxmRaiaDx+fKLMS7GgpFemS
+RrpGYr3IJHCX3IpOJaVP0x0AH2TuhykaZj6ohtljy0iEZwHbOy8yQJ3m1No6ocHW
+9p4e/8jqBdSbi/vham6hPU6sH1a7nVear0c0TqpErpQzBRKxfALjNwFunFQ047/7
+X7cfOF1K7TbU413d6S2kFSMh6AqUqYZiJpaqlHtafVA9JTmrXm0MfaM+Pt+BTuzf
+gwqAzNIejdL61cLHTGsfo8nGogsSuqav+8iLugR7bjXIIH570bWJGiOf1HoG7K0j
+VS2/fEAHg8mMIVjyFerlgNZ8HCZi2dcj1HJDlyPZkuHVj9yY/SZ5M8MXQsaX00sj
+0T5gq3vrT9OaOlW1mJAXomMpzTFHfw==
+-----END CERTIFICATE-----

+ 11 - 0
dyrpc/ssl/client/client.csr

@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBmzCCASECAQAwVTELMAkGA1UEBhMCQ04xDzANBgNVBAgMBlNoYW5YaTEQMA4G
+A1UEBwwHVGFpWXVhbjEPMA0GA1UECgwGRHVZb25nMRIwEAYDVQQDDAlsb2NhbGhv
+c3QwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARF0pVBglku0u/WeI0DpeHgCT/7g4tU
+picU0kJFTnFo7ZsBQSsJ4pjsPzT89KrBP8dpl/aPftDKEcU5wEw7OE0EIKDPYKby
+rK/1bava8SQnilTW0mJ6vmMOLZJbR+JHYjqgTTBLBgkqhkiG9w0BCQ4xPjA8MDoG
+A1UdEQQzMDGCCWxvY2FsaG9zdIIMdHlkdXlvbmcuY29tghB3d3cudHlkdXlvbmcu
+Y29thwR/AAABMAoGCCqGSM49BAMCA2gAMGUCMQC9xLdiuo11U52L1aHqGh50zZ9W
+08bp97vK0wDgWZ0Z25aM6ECzk1Wtx7DJxg0vgTkCMBOKz/G5snLZ1XOsTgwqDr57
+EO4gForuNUcwjcQLzWnk1jzpvkJ0GoljPWoptR92DA==
+-----END CERTIFICATE REQUEST-----

+ 9 - 0
dyrpc/ssl/client/client.key

@@ -0,0 +1,9 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDBfrbN23uvcUjrKsai1LBMuQylVFr7h1EAeGH2TnMAOaoqZLsilfqCu
+6cJ21wGjc36gBwYFK4EEACKhZANiAARF0pVBglku0u/WeI0DpeHgCT/7g4tUpicU
+0kJFTnFo7ZsBQSsJ4pjsPzT89KrBP8dpl/aPftDKEcU5wEw7OE0EIKDPYKbyrK/1
+bava8SQnilTW0mJ6vmMOLZJbR+JHYjo=
+-----END EC PRIVATE KEY-----

+ 22 - 0
dyrpc/ssl/client/client.pem

@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAaOgAwIBAgIJAJz6Jklhob9XMA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNV
+BAYTAkNOMQ8wDQYDVQQIDAZTaGFuWGkxEDAOBgNVBAcMB1RhaVl1YW4xDTALBgNV
+BAoMBFN0ZXAxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yNDA1MDYwMjE5NDdaFw0z
+NDA1MDQwMjE5NDdaMFUxCzAJBgNVBAYTAkNOMQ8wDQYDVQQIDAZTaGFuWGkxEDAO
+BgNVBAcMB1RhaVl1YW4xDzANBgNVBAoMBkR1WW9uZzESMBAGA1UEAwwJbG9jYWxo
+b3N0MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAERdKVQYJZLtLv1niNA6Xh4Ak/+4OL
+VKYnFNJCRU5xaO2bAUErCeKY7D80/PSqwT/HaZf2j37QyhHFOcBMOzhNBCCgz2Cm
+8qyv9W2r2vEkJ4pU1tJier5jDi2SW0fiR2I6oz4wPDA6BgNVHREEMzAxgglsb2Nh
+bGhvc3SCDHR5ZHV5b25nLmNvbYIQd3d3LnR5ZHV5b25nLmNvbYcEfwAAATANBgkq
+hkiG9w0BAQsFAAOCAgEAe1HMBidM0IBKGrXrq1XC4GKEkbmAw7Y/x3RF4XnD3UQa
+cZNhKg8Y2obw2DzOHh650qSNVQrj+l6G8dbqoCM8O+qTwwTJlGHRXlJrydVOXW2c
+2JI3s5phxMSNP7AJLhKkxcEq0rIP7swUlCXbQ0xf4D3maqBnANvNT/DL8J4afmFt
+r7OZHxdA1RkmN9uCEUasKOXv8AOqGNGi74YaEasyy7Ju6OTNsDqTtWwNZANefVid
+Z1KkGnGb9Tn4qYtWkcW8aly0kKgq+GwHXx82VKoJo7NgcA8tPW8VPWn1ftham3ln
+/jWs2xJHe4NEz8690x6QnTYqiYLHBcwC4i4pvIulh4p3k3cn/uus8CdRSVoCo/MQ
+j8+VSfBT0W8OA/PIrC/ya9GWs4lJ9wwlSsUTmeP9wTuWAbH/thAJ9DPvbAFPBEGT
+I78xAnI4seXe++JYZtcQHcjNAC5Lho36CoY5TEwYi3pTrQRwfFPb2eVhdS9YTO52
+ziPnsWNqprTF3W6w4f3rXcc3JVAKV/RX55B5bF2vZWaREcotE+FBfYDqDoJg9BNm
+UemXgWtArrOWl0mu0ILlpLfnOvUR9m5VK7tzEB3PJYlGJFt5wDlVVsDpkaodTF8O
+ngI1angkkRigp+hEe++YiuZBMek6YCjTMZp//mexl0ZIMptcm5sAB2SW0L53h4w=
+-----END CERTIFICATE-----

+ 16 - 0
dyrpc/ssl/conf/ca.conf

@@ -0,0 +1,16 @@
+[ req ]
+default_bits       = 2048
+distinguished_name = req_distinguished_name
+
+[ req_distinguished_name ]
+countryName                 = Country Name (2 letter code)
+countryName_default         = CN
+stateOrProvinceName         = State or Province Name (full name)
+stateOrProvinceName_default = ShanXi
+localityName                = Locality Name (eg, city)
+localityName_default        = TaiYuan
+organizationName            = Organization Name (eg, company)
+organizationName_default    = Step
+commonName                  = CommonName (e.g. server FQDN or YOUR name)
+commonName_max              = 64
+commonName_default          = localhost

+ 27 - 0
dyrpc/ssl/conf/client.conf

@@ -0,0 +1,27 @@
+#req 总配置
+[ req ]
+default_bits       = 2048
+distinguished_name = req_distinguished_name  #使用 req_distinguished_name配置模块
+req_extensions     = req_ext  #使用 req_ext配置模块
+
+[ req_distinguished_name ]
+countryName                 = Country Name (2 letter code)
+countryName_default         = CN
+stateOrProvinceName         = State or Province Name (full name)
+stateOrProvinceName_default = ShanXi
+localityName                = Locality Name (eg, city)
+localityName_default        = TaiYuan
+organizationName            = Organization Name (eg, company)
+organizationName_default    = DuYong
+commonName                  = Common Name (e.g. server FQDN or YOUR name)
+commonName_max              = 64
+commonName_default          = localhost    #这里的Common Name 写主要域名即可(注意:这个域名也要在alt_names的DNS.x里) 此处尤为重要,需要用该服务名字填写到客户端的代码中
+
+[ req_ext ]
+subjectAltName = @alt_names #使用 alt_names配置模块
+
+[alt_names]
+DNS.1   = localhost
+DNS.2   = tyduyong.com
+DNS.3   = www.tyduyong.com
+IP      = 127.0.0.1

+ 27 - 0
dyrpc/ssl/conf/server.conf

@@ -0,0 +1,27 @@
+#req 总配置
+[ req ]
+default_bits       = 2048
+distinguished_name = req_distinguished_name  #使用 req_distinguished_name配置模块
+req_extensions     = req_ext  #使用 req_ext配置模块
+
+[ req_distinguished_name ]
+countryName                 = Country Name (2 letter code)
+countryName_default         = CN
+stateOrProvinceName         = State or Province Name (full name)
+stateOrProvinceName_default = ShanXi
+localityName                = Locality Name (eg, city)
+localityName_default        = TaiYuan
+organizationName            = Organization Name (eg, company)
+organizationName_default    = DuYong
+commonName                  = Common Name (e.g. server FQDN or YOUR name)
+commonName_max              = 64
+commonName_default          = localhost    #这里的Common Name 写主要域名即可(注意:这个域名也要在alt_names的DNS.x里) 此处尤为重要,需要用该服务名字填写到客户端的代码中
+
+[ req_ext ]
+subjectAltName = @alt_names #使用 alt_names配置模块
+
+[alt_names]
+DNS.1   = localhost
+DNS.2   = tyduyong.com
+DNS.3   = www.tyduyong.com
+IP      = 127.0.0.1

+ 124 - 0
dyrpc/ssl/readme.md

@@ -0,0 +1,124 @@
+
+SAN(Subject Alternative Name)是 SSL 标准 x509 中定义的一个扩展。使用了 SAN 字段的 SSL 证书,可以扩
+
+展此证书支持的域名,使得一个证书可以支持多个不同域名的解析。接下来我们重新利用配置文件生成CA证书,
+
+再利用ca相关去生成服务端的证书。
+
+1. 生成根证书
+
+```conf
+[ req ]
+default_bits       = 2048
+distinguished_name = req_distinguished_name
+
+[ req_distinguished_name ]
+countryName                 = Country Name (2 letter code)
+countryName_default         = CN
+stateOrProvinceName         = State or Province Name (full name)
+stateOrProvinceName_default = ShanXi
+localityName                = Locality Name (eg, city)
+localityName_default        = TaiYuan
+organizationName            = Organization Name (eg, company)
+organizationName_default    = Step
+commonName                  = CommonName (e.g. server FQDN or YOUR name)
+commonName_max              = 64
+commonName_default          = localhost
+```
+
+
+```bash
+cd ssl
+# 生成ca秘钥,得到ca.key
+openssl genrsa -out ./ca/ca.key 4096
+# 生成ca证书签发请求,得到ca.csr
+openssl req -new -sha256 -out ./ca/ca.csr -key ./ca/ca.key -config ./conf/ca.conf
+# 成ca根证书,得到ca.pem
+openssl x509 -req -sha256 -days 3650 -in ./ca/ca.csr -signkey ./ca/ca.key -out ./ca/ca.pem
+```
+
+2. 生成服务端证书
+
+```conf
+#req 总配置
+[ req ]
+default_bits       = 2048
+distinguished_name = req_distinguished_name  #使用 req_distinguished_name配置模块
+req_extensions     = req_ext  #使用 req_ext配置模块
+
+[ req_distinguished_name ]
+countryName                 = Country Name (2 letter code)
+countryName_default         = CN
+stateOrProvinceName         = State or Province Name (full name)
+stateOrProvinceName_default = ShanXi
+localityName                = Locality Name (eg, city)
+localityName_default        = TaiYuan
+organizationName            = Organization Name (eg, company)
+organizationName_default    = DuYong
+commonName                  = Common Name (e.g. server FQDN or YOUR name)
+commonName_max              = 64
+commonName_default          = localhost    #这里的Common Name 写主要域名即可(注意:这个域名也要在alt_names的DNS.x里) 此处尤为重要,需要用该服务名字填写到客户端的代码中
+
+[ req_ext ]
+subjectAltName = @alt_names #使用 alt_names配置模块
+
+[alt_names]
+DNS.1   = localhost
+DNS.2   = tyduyong.com
+DNS.3   = www.tyduyong.com
+IP      = 127.0.0.1
+```
+
+
+```bash
+# 生成秘钥,得到server.key
+openssl genrsa -out ./server/server.key 2048
+# 生成证书签发请求,得到server.csr
+openssl req -new -sha256 -out ./server/server.csr -key ./server/server.key -config ./conf/server.conf
+# 用CA证书生成服务端证书,得到server.pem
+openssl x509 -req -sha256 -days 3650 -CA ./ca/ca.pem -CAkey ./ca/ca.key -CAcreateserial -in ./server/server.csr -out ./server/server.pem -extensions req_ext -extfile ./conf/server.conf
+```
+
+
+3. 生成客户端证书
+
+```conf
+#req 总配置
+[ req ]
+default_bits       = 2048
+distinguished_name = req_distinguished_name  #使用 req_distinguished_name配置模块
+req_extensions     = req_ext  #使用 req_ext配置模块
+
+[ req_distinguished_name ]
+countryName                 = Country Name (2 letter code)
+countryName_default         = CN
+stateOrProvinceName         = State or Province Name (full name)
+stateOrProvinceName_default = ShanXi
+localityName                = Locality Name (eg, city)
+localityName_default        = TaiYuan
+organizationName            = Organization Name (eg, company)
+organizationName_default    = DuYong
+commonName                  = Common Name (e.g. server FQDN or YOUR name)
+commonName_max              = 64
+commonName_default          = localhost    #这里的Common Name 写主要域名即可(注意:这个域名也要在alt_names的DNS.x里) 此处尤为重要,需要用该服务名字填写到客户端的代码中
+
+[ req_ext ]
+subjectAltName = @alt_names #使用 alt_names配置模块
+
+[alt_names]
+DNS.1   = localhost
+DNS.2   = tyduyong.com
+DNS.3   = www.tyduyong.com
+IP      = 127.0.0.1
+```
+
+```bash
+# 生成秘钥,得到client.key
+openssl ecparam -genkey -name secp384r1 -out ./client/client.key
+# 生成证书签发请求,得到client.csr
+openssl req -new -sha256 -out ./client/client.csr -key ./client/client.key -config ./conf/client.conf
+# 用CA证书生成客户端证书,得到client.pem
+openssl x509 -req -sha256 -days 3650 -CA ./ca/ca.pem -CAkey ./ca/ca.key -CAcreateserial -in ./client/client.csr -out ./client/client.pem -extensions req_ext -extfile ./conf/client.conf
+
+
+```

+ 18 - 0
dyrpc/ssl/server/server.csr

@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIC5zCCAc8CAQAwVTELMAkGA1UEBhMCQ04xDzANBgNVBAgMBlNoYW5YaTEQMA4G
+A1UEBwwHVGFpWXVhbjEPMA0GA1UECgwGRHVZb25nMRIwEAYDVQQDDAlsb2NhbGhv
+c3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzE6wZUEkDroC5n3EO
+BlUgPppsiJbmeYt3JDw0pVUUlvgUPWgQX6CkGsRqYZvn52BWeNwTZZ7vrr0I5bCV
+Bx8oQ517VU8K9j9Xrzryh6DL+lbS4u/QcD/FQNy+cNlBcaTYYduPf92LeOZ4jBih
+J0tL0cn5N5UHogfYNXrwcG6PRWk6cdoFK3RQpXMDZoJEbaKvxuvNn8P+zBczC3jj
+uuU/KHIMrrib3pMrSQixYZPFdaEya+as3Wv2w6kt7F8RHFQLz/Q+8fL/yHQOdojW
+oaiiyNLF45Ik1kMPoGzpvzOOW+CHPFcZeaWrbBE5sE50vT0FF/wGfcDR6ysppmmD
+WbtbAgMBAAGgTTBLBgkqhkiG9w0BCQ4xPjA8MDoGA1UdEQQzMDGCCWxvY2FsaG9z
+dIIMdHlkdXlvbmcuY29tghB3d3cudHlkdXlvbmcuY29thwR/AAABMA0GCSqGSIb3
+DQEBCwUAA4IBAQBxft1AemqW9mld2aS3KyukDnCPP9FTJhW4KTCURlDGhSa8IYN4
+JYJvZxDkfO6koDdt+ukSh4fpcD9+jAKj9L+iwTyzTmHNJHZ+tSAbu2fFtcYjbjww
+jDcsgE4GDdfDvqfzgt3wpUuEB4Tj8nx+oS++uI5oZGgeHoE1lJYzgieEit6pOe8E
+/Pv+/0+8MvDi1CA+wamIPaLjqah+0bex70qW6yZZfaM4ybQczb8hC/kkUiMVfOhu
+YdclSq0hK2eMh5gXlLW2dXudhx2dODAZcM9YLa3y5vgeQT6Sz+8j6UxvXFeVV65I
+D+q31i5JBVQzUg+OPX3XAQG8vLREUOm/6a7q
+-----END CERTIFICATE REQUEST-----

+ 27 - 0
dyrpc/ssl/server/server.key

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAsxOsGVBJA66AuZ9xDgZVID6abIiW5nmLdyQ8NKVVFJb4FD1o
+EF+gpBrEamGb5+dgVnjcE2We7669COWwlQcfKEOde1VPCvY/V6868oegy/pW0uLv
+0HA/xUDcvnDZQXGk2GHbj3/di3jmeIwYoSdLS9HJ+TeVB6IH2DV68HBuj0VpOnHa
+BSt0UKVzA2aCRG2ir8brzZ/D/swXMwt447rlPyhyDK64m96TK0kIsWGTxXWhMmvm
+rN1r9sOpLexfERxUC8/0PvHy/8h0DnaI1qGoosjSxeOSJNZDD6Bs6b8zjlvghzxX
+GXmlq2wRObBOdL09BRf8Bn3A0esrKaZpg1m7WwIDAQABAoIBAFdG/ji0JXHS6dAO
+QmaIdZKqkE7XX1xi3rMpiOJLtiS705rhtsdMJBn3JcWHXxnubciXTQNzIrxEWMNu
+Vtq7Rtcz5RwIHucDzyloMP2lVpwznX9YtXLMUnhLvYpfq7M2tRX007KjqhFg0krs
+VNCuOwdv7tU03sCCmvooTovC8E+Ivxlc192S7rqV04CeU/ORljXOIdUuEOjnVNWc
+5sZ+hB1YNqmf0OiruxI78LNIIHVSEXQG1HBS65ca8Gssr5szGzC+d28LyT7OzGXU
+fWKUhxn6xk+MnMWAxz/MNZ9MBRte5o9JCitmMvms33lEuyUezjZA2BDfA++9c51A
+SpjKUIkCgYEA2oGhYJODoUySx8TZWeKF6ioClqTsRkML48wJy5EkF+iOwfDhOXWx
+v7OR5bqX70LNSqvsccnN4uUDtiaUeyJUkcKMvgZZvMeSS3A+CIxUjrWoeD0NeoGX
+M/4cCzNDHnB4gvzG3KNNl4juMR/Nbl2LH4CAfvQ97wLuTsaR/j1H1pcCgYEA0c4D
+jwpazs/gUcOIsF64DwXbOctGEI5s341eDWBlbRsgyPKcZuJt2A91hSa5thlnPmh9
+ABYcqAOhrF6XYptx6NalXgraPDW6BCE3EqGptu6DkPXUcl0xWPngu4vhic8L9fbi
+0gDlnD7pzyggeT8FhsR8MAslxeiXgt1GGIlYvd0CgYBQyPiHIkLaUds6rJbHWq60
+IpAObi9E0ukEcZ11e9XiWQLexVYfzlnHTHa2fsRJm2MXJnUmpLvQFWfH4n+m/sxR
+j6JFZ0eqOgbmiTsGIgvpL1R4D+p5zou+l0Z7BZrdGCwWEarcTCwVyHR4CRAEq+UR
+4oqfZWG4ilbdHSFA5Bs5RQKBgEUeoQ+D8szFsXped+7bFbplTIcqz+dudLHlqgGw
+K1oZoOBzBVHj8RpIZYg7bN1wWxI1bFEV99TmdWILO8aRvaJe7NYhryo87Q6lPraV
+qgsJYzDjvFz9FN/iWsaO2/wByUf8UVesUfj6xR6pcqFfQNvYaa2OTqB380p6ybgV
+r7XFAoGADkI/Ni9b4QXPqn54/bSZS0jknVBGRUcGv6P+ohF9CbUOSFkpA9vOdTvB
+mRaNOt7vt5mSXj/48vzcezPr3jXTUqn0PSEV2wIAikXg4apTKUPT7C0/SW3HCCkV
+n0bnwF1SnhntC+OxWY7Yjcdhg17EDGohrHm7rSIXRlHgucBDqvE=
+-----END RSA PRIVATE KEY-----

+ 26 - 0
dyrpc/ssl/server/server.pem

@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEaTCCAlGgAwIBAgIJAJz6Jklhob9WMA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNV
+BAYTAkNOMQ8wDQYDVQQIDAZTaGFuWGkxEDAOBgNVBAcMB1RhaVl1YW4xDTALBgNV
+BAoMBFN0ZXAxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yNDA1MDYwMjE5MjVaFw0z
+NDA1MDQwMjE5MjVaMFUxCzAJBgNVBAYTAkNOMQ8wDQYDVQQIDAZTaGFuWGkxEDAO
+BgNVBAcMB1RhaVl1YW4xDzANBgNVBAoMBkR1WW9uZzESMBAGA1UEAwwJbG9jYWxo
+b3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsxOsGVBJA66AuZ9x
+DgZVID6abIiW5nmLdyQ8NKVVFJb4FD1oEF+gpBrEamGb5+dgVnjcE2We7669COWw
+lQcfKEOde1VPCvY/V6868oegy/pW0uLv0HA/xUDcvnDZQXGk2GHbj3/di3jmeIwY
+oSdLS9HJ+TeVB6IH2DV68HBuj0VpOnHaBSt0UKVzA2aCRG2ir8brzZ/D/swXMwt4
+47rlPyhyDK64m96TK0kIsWGTxXWhMmvmrN1r9sOpLexfERxUC8/0PvHy/8h0DnaI
+1qGoosjSxeOSJNZDD6Bs6b8zjlvghzxXGXmlq2wRObBOdL09BRf8Bn3A0esrKaZp
+g1m7WwIDAQABoz4wPDA6BgNVHREEMzAxgglsb2NhbGhvc3SCDHR5ZHV5b25nLmNv
+bYIQd3d3LnR5ZHV5b25nLmNvbYcEfwAAATANBgkqhkiG9w0BAQsFAAOCAgEAoyMM
+DU5lltR0QD5E1hAbbiXUbgO76OmMjbhPm+3Xa5ARHpZ/f7XsQHwPeZODPQP+d/vi
+PnMgC1KfBFFkR0i6T1fJivOlp2ESF+9RlCTVeaE2blB7pvq9T++Sdu/BTvU9LkN/
+KxkQfi+6CAysVmFeW3hgssUPZHrUBTxOKmJO8SmPgq5gYXFBlFYSWUt78oN/pNbO
+cWgjcK+ALiLvO5YaV28JUSD4lv+HYHlq9DP0vXEA6UgaUdwb+EskER6YxOm7487w
+qjLmIdyelPB5qTWGF90v+gqtg9rT9Aj3jt4qNexa+NE//18Yb5k+ArY2xN3+PewD
+oXMMPZlXnC5I/g82TipbbqH5fCPg2CHO+Fa6tOXq3iP1Aju6z2LT3orEMKJsf3/B
+6NZCqQjyFCtlJBt+yTBkhzc8+zLgkcu4+Jp/U1zquBLNOUTGkd0gCgdMOGrFoFZl
+PSo7leKvVGQPuCqroTUxCzj6qQoYmZtXJuuLUdnAfozle3deqhZliUku6ZwSVL/R
+X+2j9lcZU6O10MpyAtMpt3Cd66ncFXKW+PZJU5kU++8B8+MZXP091v3AqXZ+fzMu
+6wS9PmJ3x9p6mEgP1D3D7bnvUEV6GN/OtKgsdT6hd3qGwknBn21qsXoY4DhMoAEa
+19Fp8gSz6OgVuESlKFDFURKo6JbBo8iJi3Xx0/c=
+-----END CERTIFICATE-----

+ 17 - 0
go.mod

@@ -0,0 +1,17 @@
+module dy-test
+
+go 1.22.0
+
+require (
+	github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0
+	google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d
+	google.golang.org/grpc v1.64.0
+	google.golang.org/protobuf v1.34.2
+)
+
+require (
+	golang.org/x/net v0.23.0 // indirect
+	golang.org/x/sys v0.18.0 // indirect
+	golang.org/x/text v0.15.0 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect
+)

+ 18 - 0
go.sum

@@ -0,0 +1,18 @@
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
+golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
+golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d h1:Aqf0fiIdUQEj0Gn9mKFFXoQfTTEaNopWpfVyYADxiSg=
+google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Od4k8V1LQSizPRUK4OzZ7TBE/20k+jPczUDAEyvn69Y=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 h1:Di6ANFilr+S60a4S61ZM00vLdw0IrQOSMS2/6mrnOU0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
+google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=