allow to catch response headers #63
@ -26,7 +26,7 @@ service Example {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
option (micro.api.http) = { post: "/v1/example/call/{name}"; body: "*"; };
|
option (micro.api.http) = { post: "/v1/example/call/{name}"; body: "*"; };
|
||||||
option (micro.api.micro_method) = { timeout: 5; };
|
option (micro.api.micro_method) = { timeout: "5s"; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2
go.mod
2
go.mod
@ -4,7 +4,7 @@ go 1.16
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fatih/structtag v1.2.0
|
github.com/fatih/structtag v1.2.0
|
||||||
go.unistack.org/micro-proto/v3 v3.2.7
|
go.unistack.org/micro-proto/v3 v3.3.1
|
||||||
golang.org/x/tools v0.3.0
|
golang.org/x/tools v0.3.0
|
||||||
google.golang.org/protobuf v1.28.1
|
google.golang.org/protobuf v1.28.1
|
||||||
)
|
)
|
||||||
|
8
go.sum
8
go.sum
@ -39,8 +39,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
|||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/gnostic v0.6.6 h1:MVSM2r2j9aRUvYNym66JGW96Ddd5MN4sTi59yktb6yk=
|
github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0=
|
||||||
github.com/google/gnostic v0.6.6/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E=
|
github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
@ -68,8 +68,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:
|
|||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.unistack.org/micro-proto/v3 v3.2.7 h1:zG6d69kHc+oij2lwQ3AfrCgdjiEVRG2A7TlsxjusWs4=
|
go.unistack.org/micro-proto/v3 v3.3.1 h1:nQ0MtWvP2G3QrpOgawVOPhpZZYkq6umTGDqs8FxJYIo=
|
||||||
go.unistack.org/micro-proto/v3 v3.2.7/go.mod h1:ZltVWNECD5yK+40+OCONzGw4OtmSdTpVi8/KFgo9dqM=
|
go.unistack.org/micro-proto/v3 v3.3.1/go.mod h1:cwRyv8uInM2I7EbU7O8Fx2Ls3N90Uw9UCCcq4olOdfE=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
3
main.go
3
main.go
@ -18,6 +18,7 @@ var (
|
|||||||
flagComponents = flagSet.String("components", "micro|rpc|http|client|server|openapiv3", "specify components to generate")
|
flagComponents = flagSet.String("components", "micro|rpc|http|client|server|openapiv3", "specify components to generate")
|
||||||
flagTagPath = flagSet.String("tag_path", "", "tag rewriting dir")
|
flagTagPath = flagSet.String("tag_path", "", "tag rewriting dir")
|
||||||
flagOpenapiFile = flagSet.String("openapi_file", "apidocs.swagger.json", "openapi file name")
|
flagOpenapiFile = flagSet.String("openapi_file", "apidocs.swagger.json", "openapi file name")
|
||||||
|
flagReflection = flagSet.Bool("reflection", false, "enable server reflection support")
|
||||||
flagHelp = flagSet.Bool("help", false, "display help message")
|
flagHelp = flagSet.Bool("help", false, "display help message")
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ type Generator struct {
|
|||||||
fieldaligment bool
|
fieldaligment bool
|
||||||
tagPath string
|
tagPath string
|
||||||
openapiFile string
|
openapiFile string
|
||||||
|
reflection bool
|
||||||
plugin *protogen.Plugin
|
plugin *protogen.Plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +60,7 @@ func (g *Generator) Generate(plugin *protogen.Plugin) error {
|
|||||||
g.fieldaligment = *flagFieldaligment
|
g.fieldaligment = *flagFieldaligment
|
||||||
g.tagPath = *flagTagPath
|
g.tagPath = *flagTagPath
|
||||||
g.openapiFile = *flagOpenapiFile
|
g.openapiFile = *flagOpenapiFile
|
||||||
|
g.reflection = *flagReflection
|
||||||
plugin.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)
|
plugin.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)
|
||||||
|
|
||||||
var genClient bool
|
var genClient bool
|
||||||
|
20
micro.go
20
micro.go
@ -1,6 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"google.golang.org/protobuf/compiler/protogen"
|
"google.golang.org/protobuf/compiler/protogen"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,8 +24,10 @@ func (g *Generator) microGenerate(component string, plugin *protogen.Plugin, gen
|
|||||||
gfile := plugin.NewGeneratedFile(gname, path)
|
gfile := plugin.NewGeneratedFile(gname, path)
|
||||||
|
|
||||||
gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.")
|
gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.")
|
||||||
gfile.P("// protoc-gen-go-micro version: " + versionComment)
|
gfile.P("// versions:")
|
||||||
gfile.P("// source: ", file.Proto.GetName())
|
gfile.P("// - protoc-gen-go-micro " + versionComment)
|
||||||
|
gfile.P("// - protoc ", protocVersion(plugin))
|
||||||
|
gfile.P("// source: ", file.Desc.Path())
|
||||||
gfile.P()
|
gfile.P()
|
||||||
gfile.P("package ", file.GoPackageName)
|
gfile.P("package ", file.GoPackageName)
|
||||||
gfile.P()
|
gfile.P()
|
||||||
@ -50,3 +54,15 @@ func (g *Generator) microGenerate(component string, plugin *protogen.Plugin, gen
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func protocVersion(plugin *protogen.Plugin) string {
|
||||||
|
v := plugin.Request.GetCompilerVersion()
|
||||||
|
if v == nil {
|
||||||
|
return "(unknown)"
|
||||||
|
}
|
||||||
|
var suffix string
|
||||||
|
if s := v.GetSuffix(); s != "" {
|
||||||
|
suffix = "-" + s
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("v%d.%d.%d%s", v.GetMajor(), v.GetMinor(), v.GetPatch(), suffix)
|
||||||
|
}
|
||||||
|
3
rpc.go
3
rpc.go
@ -45,6 +45,9 @@ func (g *Generator) rpcGenerate(component string, plugin *protogen.Plugin, genCl
|
|||||||
g.generateServiceServerMethods(gfile, service)
|
g.generateServiceServerMethods(gfile, service)
|
||||||
g.generateServiceRegister(gfile, service)
|
g.generateServiceRegister(gfile, service)
|
||||||
}
|
}
|
||||||
|
if component == "grpc" && g.reflection {
|
||||||
|
g.generateServiceDesc(gfile, file, service)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
70
util.go
70
util.go
@ -4,7 +4,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
api_options "go.unistack.org/micro-proto/v3/api"
|
api_options "go.unistack.org/micro-proto/v3/api"
|
||||||
v2 "go.unistack.org/micro-proto/v3/openapiv2"
|
v2 "go.unistack.org/micro-proto/v3/openapiv2"
|
||||||
@ -213,8 +215,14 @@ func (g *Generator) generateServiceClientMethods(gfile *protogen.GeneratedFile,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if rule, ok := getMicroApiMethod(method); ok {
|
if rule, ok := getMicroApiMethod(method); ok {
|
||||||
if rule.Timeout > 0 {
|
if rule.Timeout != "" {
|
||||||
gfile.P("opts = append(opts, ", microClientPackage.Ident("WithRequestTimeout"), "(", timePackage.Ident("Second"), "*", rule.Timeout, "))")
|
td, err := time.ParseDuration(rule.Timeout)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("parse duration error %s\n", err.Error())
|
||||||
|
} else {
|
||||||
|
gfile.P("td := uint64(", td.Nanoseconds(), ")")
|
||||||
|
gfile.P("opts = append(opts, ", microClientPackage.Ident("WithRequestTimeout"), "(", timePackage.Ident("Nanosecond"), "* ", "td", "))")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +295,11 @@ func (g *Generator) generateServiceClientMethods(gfile *protogen.GeneratedFile,
|
|||||||
gfile.P()
|
gfile.P()
|
||||||
|
|
||||||
if method.Desc.IsStreamingClient() {
|
if method.Desc.IsStreamingClient() {
|
||||||
|
gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") Header() ", microMetadataPackage.Ident("Metadata"), "{")
|
||||||
|
gfile.P("return s.stream.Response().Header()")
|
||||||
|
gfile.P("}")
|
||||||
|
gfile.P()
|
||||||
|
|
||||||
gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") Send(msg *", gfile.QualifiedGoIdent(method.Input.GoIdent), ") error {")
|
gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") Send(msg *", gfile.QualifiedGoIdent(method.Input.GoIdent), ") error {")
|
||||||
gfile.P("return s.stream.Send(msg)")
|
gfile.P("return s.stream.Send(msg)")
|
||||||
gfile.P("}")
|
gfile.P("}")
|
||||||
@ -319,12 +332,18 @@ func (g *Generator) generateServiceServerMethods(gfile *protogen.GeneratedFile,
|
|||||||
for _, method := range service.Methods {
|
for _, method := range service.Methods {
|
||||||
generateServerFuncSignature(gfile, serviceName, method, true)
|
generateServerFuncSignature(gfile, serviceName, method, true)
|
||||||
if rule, ok := getMicroApiMethod(method); ok {
|
if rule, ok := getMicroApiMethod(method); ok {
|
||||||
if rule.Timeout > 0 {
|
if rule.Timeout != "" {
|
||||||
|
td, err := time.ParseDuration(rule.Timeout)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("parse duration error %s\n", err.Error())
|
||||||
|
} else {
|
||||||
gfile.P("var cancel ", contextPackage.Ident("CancelFunc"))
|
gfile.P("var cancel ", contextPackage.Ident("CancelFunc"))
|
||||||
gfile.P("ctx, cancel = ", contextPackage.Ident("WithTimeout"), "(ctx, ", timePackage.Ident("Second"), "*", rule.Timeout, ")")
|
gfile.P("td := ", timePackage.Ident("Duration"), "(", td.Nanoseconds(), ")")
|
||||||
|
gfile.P("ctx, cancel = ", contextPackage.Ident("WithTimeout"), "(ctx, ", "td", ")")
|
||||||
gfile.P("defer cancel()")
|
gfile.P("defer cancel()")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() {
|
if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() {
|
||||||
if !method.Desc.IsStreamingClient() {
|
if !method.Desc.IsStreamingClient() {
|
||||||
gfile.P("msg := &", gfile.QualifiedGoIdent(method.Input.GoIdent), "{}")
|
gfile.P("msg := &", gfile.QualifiedGoIdent(method.Input.GoIdent), "{}")
|
||||||
@ -598,6 +617,7 @@ func (g *Generator) generateServiceClientStreamInterface(gfile *protogen.Generat
|
|||||||
}
|
}
|
||||||
gfile.P("Close() error")
|
gfile.P("Close() error")
|
||||||
if method.Desc.IsStreamingClient() {
|
if method.Desc.IsStreamingClient() {
|
||||||
|
gfile.P("Header() ", microMetadataPackage.Ident("Metadata"))
|
||||||
gfile.P("Send(msg *", gfile.QualifiedGoIdent(method.Input.GoIdent), ") error")
|
gfile.P("Send(msg *", gfile.QualifiedGoIdent(method.Input.GoIdent), ") error")
|
||||||
}
|
}
|
||||||
if method.Desc.IsStreamingServer() {
|
if method.Desc.IsStreamingServer() {
|
||||||
@ -798,3 +818,45 @@ func getGoIdentByMessage(messages []*protogen.Message, msg string) (protogen.GoI
|
|||||||
}
|
}
|
||||||
return protogen.GoIdent{}, fmt.Errorf("not found")
|
return protogen.GoIdent{}, fmt.Errorf("not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Generator) generateServiceDesc(gfile *protogen.GeneratedFile, file *protogen.File, service *protogen.Service) {
|
||||||
|
serviceName := service.GoName
|
||||||
|
|
||||||
|
gfile.P("// ", serviceName, "_ServiceDesc", " is the ", grpcPackage.Ident("ServiceDesc"), " for ", serviceName, " service.")
|
||||||
|
gfile.P("// It's only intended for direct use with ", grpcPackage.Ident("RegisterService"), ",")
|
||||||
|
gfile.P("// and not to be introspected or modified (even as a copy)")
|
||||||
|
gfile.P("var ", serviceName, "_ServiceDesc", " = ", grpcPackage.Ident("ServiceDesc"), " {")
|
||||||
|
gfile.P("ServiceName: ", strconv.Quote(string(service.Desc.FullName())), ",")
|
||||||
|
gfile.P("HandlerType: (*", serviceName, "Server)(nil),")
|
||||||
|
gfile.P("Methods: []", grpcPackage.Ident("MethodDesc"), "{")
|
||||||
|
for _, method := range service.Methods {
|
||||||
|
if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gfile.P("{")
|
||||||
|
gfile.P("MethodName: ", strconv.Quote(string(method.Desc.Name())), ",")
|
||||||
|
gfile.P("Handler: ", method.GoName, ",")
|
||||||
|
gfile.P("},")
|
||||||
|
}
|
||||||
|
gfile.P("},")
|
||||||
|
gfile.P("Streams: []", grpcPackage.Ident("StreamDesc"), "{")
|
||||||
|
for _, method := range service.Methods {
|
||||||
|
if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gfile.P("{")
|
||||||
|
gfile.P("StreamName: ", strconv.Quote(string(method.Desc.Name())), ",")
|
||||||
|
gfile.P("Handler: ", method.GoName, ",")
|
||||||
|
if method.Desc.IsStreamingServer() {
|
||||||
|
gfile.P("ServerStreams: true,")
|
||||||
|
}
|
||||||
|
if method.Desc.IsStreamingClient() {
|
||||||
|
gfile.P("ClientStreams: true,")
|
||||||
|
}
|
||||||
|
gfile.P("},")
|
||||||
|
}
|
||||||
|
gfile.P("},")
|
||||||
|
gfile.P("Metadata: \"", file.Desc.Path(), "\",")
|
||||||
|
gfile.P("}")
|
||||||
|
gfile.P()
|
||||||
|
}
|
||||||
|
@ -12,12 +12,14 @@ var (
|
|||||||
chiPackage = protogen.GoImportPath("github.com/go-chi/chi/v5")
|
chiPackage = protogen.GoImportPath("github.com/go-chi/chi/v5")
|
||||||
chiMiddlewarePackage = protogen.GoImportPath("github.com/go-chi/chi/v5/middleware")
|
chiMiddlewarePackage = protogen.GoImportPath("github.com/go-chi/chi/v5/middleware")
|
||||||
microApiPackage = protogen.GoImportPath("go.unistack.org/micro/v3/api")
|
microApiPackage = protogen.GoImportPath("go.unistack.org/micro/v3/api")
|
||||||
|
microMetadataPackage = protogen.GoImportPath("go.unistack.org/micro/v3/metadata")
|
||||||
microClientPackage = protogen.GoImportPath("go.unistack.org/micro/v3/client")
|
microClientPackage = protogen.GoImportPath("go.unistack.org/micro/v3/client")
|
||||||
microServerPackage = protogen.GoImportPath("go.unistack.org/micro/v3/server")
|
microServerPackage = protogen.GoImportPath("go.unistack.org/micro/v3/server")
|
||||||
microClientHttpPackage = protogen.GoImportPath("go.unistack.org/micro-client-http/v3")
|
microClientHttpPackage = protogen.GoImportPath("go.unistack.org/micro-client-http/v3")
|
||||||
microServerHttpPackage = protogen.GoImportPath("go.unistack.org/micro-server-http/v3")
|
microServerHttpPackage = protogen.GoImportPath("go.unistack.org/micro-server-http/v3")
|
||||||
microCodecPackage = protogen.GoImportPath("go.unistack.org/micro/v3/codec")
|
microCodecPackage = protogen.GoImportPath("go.unistack.org/micro/v3/codec")
|
||||||
microErrorsPackage = protogen.GoImportPath("go.unistack.org/micro/v3/errors")
|
microErrorsPackage = protogen.GoImportPath("go.unistack.org/micro/v3/errors")
|
||||||
|
grpcPackage = protogen.GoImportPath("google.golang.org/grpc")
|
||||||
timePackage = protogen.GoImportPath("time")
|
timePackage = protogen.GoImportPath("time")
|
||||||
deprecationComment = "// Deprecated: Do not use."
|
deprecationComment = "// Deprecated: Do not use."
|
||||||
versionComment = "v3.5.3"
|
versionComment = "v3.5.3"
|
||||||
|
Loading…
Reference in New Issue
Block a user