Compare commits

...

16 Commits

Author SHA1 Message Date
0e902b1022 update
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-06-22 01:34:46 +03:00
81bbbf55e6 change name, add comment
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-06-22 01:34:06 +03:00
c6caa0d3ac tag fix
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-18 14:03:21 +03:00
5ecc4986dd dont tag if tag_path is empty
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-11 09:07:12 +03:00
9ed1ca9a89 add info to readme
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-08 12:53:14 +03:00
805b52cf8d add tags example
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-08 12:46:02 +03:00
d41fa1a64f add tag support
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-08 00:06:40 +03:00
f69088bd27 fallback to generate client and server
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-30 18:30:58 +03:00
be4eac21df fix example
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-26 16:04:08 +03:00
fcd8dd1f7c minor changes for generator
* allow to split client and server generation
* allow to override options for handler

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-26 15:00:55 +03:00
c7ec840ac0 remove some runtime allocaions
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-23 16:56:11 +03:00
bce3839877 fix http client generation without openapiv2 annotation
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-19 13:00:00 +03:00
Renovate Bot
4d2af78ba7 Update module google.golang.org/protobuf to v1.26.0 2021-03-19 03:24:49 +00:00
298f123492 extract variables to dedicated file
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-02-28 23:42:00 +03:00
254448bf74 add client request timeout option support
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-02-28 01:42:29 +03:00
7b349ba1ca update micro-proto
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-02-28 00:38:57 +03:00
13 changed files with 414 additions and 73 deletions

View File

@@ -1,4 +1,4 @@
# `protoc-gen-micro` # `protoc-gen-go-micro`
protobuf plugin to generate helper code for micro framework protobuf plugin to generate helper code for micro framework
A generic **code**/script/data generator based on [Protobuf](https://developers.google.com/protocol-buffers/). A generic **code**/script/data generator based on [Protobuf](https://developers.google.com/protocol-buffers/).
@@ -15,11 +15,12 @@ $> protoc --micro_out=debug=true,components="micro|http":. input.proto
| Option | Default Value | Accepted Values | Description | Option | Default Value | Accepted Values | Description
|-----------------------|---------------|---------------------------|----------------------- |-----------------------|---------------|---------------------------|-----------------------
| `tag_path` | `.` | `any local path` | path contains generated protobuf code that needs to be tagged
| `debug`               | *false*       | `true` or `false` | if *true*, `protoc` will generate a more verbose output | `debug`               | *false*       | `true` or `false` | if *true*, `protoc` will generate a more verbose output
| `components` | `micro` | `micro rpc http chi gorilla` | some values cant coexists like gorilla/chi or rpc/http, values must be concatinated with pipe symbol | `components` | `micro` | `micro rpc http chi gorilla client server` | some values can't coexists like gorilla/chi or rpc/http, values must be concatinated with pipe symbol
## Install ## Install
* Install the **go** compiler and tools from https://golang.org/doc/install * Install the **go** compiler and tools from https://golang.org/doc/install
* Install **protoc-gen-go**: `go get google.golang.org/protobuf/cmd/protoc-gen-go` * Install **protoc-gen-go**: `go get google.golang.org/protobuf/cmd/protoc-gen-go`
* Install **protoc-gen-micro**: `go get github.com/unistack-org/protoc-gen-micro/v3` * Install **protoc-gen-go-micro**: `go get github.com/unistack-org/protoc-gen-go-micro/v3`

159
ast.go Normal file
View File

@@ -0,0 +1,159 @@
package main
import (
"go/ast"
"go/format"
"go/parser"
"go/token"
"os"
"path/filepath"
"strings"
"github.com/fatih/structtag"
tag_options "github.com/unistack-org/micro-proto/tag"
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/proto"
)
var (
astFields = make(map[string]map[string]map[string]*structtag.Tags) // map proto file with proto message ast struct
)
func (g *Generator) astGenerate(plugin *protogen.Plugin) error {
if g.tagPath == "" {
return nil
}
for _, file := range plugin.Files {
if !file.Generate {
continue
}
for _, message := range file.Messages {
for _, field := range message.Fields {
if field.Desc.Options() == nil {
continue
}
if !proto.HasExtension(field.Desc.Options(), tag_options.E_Tags) {
continue
}
opts := proto.GetExtension(field.Desc.Options(), tag_options.E_Tags)
if opts != nil {
fpath := filepath.Join(g.tagPath, file.GeneratedFilenamePrefix+".pb.go")
mp, ok := astFields[fpath]
if !ok {
mp = make(map[string]map[string]*structtag.Tags)
}
nmp, ok := mp[message.GoIdent.GoName]
if !ok {
nmp = make(map[string]*structtag.Tags)
}
tags, err := structtag.Parse(opts.(string))
if err != nil {
return err
}
nmp[field.GoName] = tags
mp[message.GoIdent.GoName] = nmp
astFields[fpath] = mp
}
}
}
}
for file, mp := range astFields {
fset := token.NewFileSet()
pf, err := parser.ParseFile(fset, file, nil, parser.AllErrors|parser.ParseComments)
if err != nil {
return err
}
r := retag{}
f := func(n ast.Node) ast.Visitor {
if r.err != nil {
return nil
}
if v, ok := n.(*ast.TypeSpec); ok {
r.fields = mp[v.Name.Name]
return r
}
return nil
}
ast.Walk(structVisitor{f}, pf)
if r.err != nil {
return err
}
fp, err := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC, os.FileMode(0644))
if err != nil {
return err
}
if err = format.Node(fp, fset, pf); err != nil {
fp.Close()
return err
}
if err = fp.Close(); err != nil {
return err
}
}
return nil
}
type retag struct {
err error
fields map[string]*structtag.Tags
}
func (v retag) Visit(n ast.Node) ast.Visitor {
if v.err != nil {
return nil
}
if f, ok := n.(*ast.Field); ok {
if len(f.Names) == 0 {
return nil
}
newTags := v.fields[f.Names[0].String()]
if newTags == nil {
return nil
}
if f.Tag == nil {
f.Tag = &ast.BasicLit{
Kind: token.STRING,
}
}
oldTags, err := structtag.Parse(strings.Trim(f.Tag.Value, "`"))
if err != nil {
v.err = err
return nil
}
for _, t := range newTags.Tags() {
oldTags.Set(t)
}
f.Tag.Value = "`" + oldTags.String() + "`"
return nil
}
return v
}
type structVisitor struct {
visitor func(n ast.Node) ast.Visitor
}
func (v structVisitor) Visit(n ast.Node) ast.Visitor {
if tp, ok := n.(*ast.TypeSpec); ok {
if _, ok := tp.Type.(*ast.StructType); ok {
ast.Walk(v.visitor(n), n)
return nil // This will ensure this struct is no longer traversed
}
}
return v
}

3
chi.go
View File

@@ -30,7 +30,8 @@ func (g *Generator) chiGenerate(component string, plugin *protogen.Plugin) error
} }
gfile := plugin.NewGeneratedFile(gname, path) gfile := plugin.NewGeneratedFile(gname, path)
gfile.P("// Code generated by protoc-gen-micro") gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.")
gfile.P("// protoc-gen-go-micro version: " + versionComment)
gfile.P("package ", file.GoPackageName) gfile.P("package ", file.GoPackageName)
gfile.P() gfile.P()

44
example/example.proto Normal file
View File

@@ -0,0 +1,44 @@
syntax = "proto3";
package example;
option go_package = "github.com/unistack-org/protoc-gen-go-micro/v3/example;examplepb";
import "tag/tag.proto";
import "api/annotations.proto";
import "openapiv2/annotations.proto";
import "google/protobuf/wrappers.proto";
service Example {
rpc Call(CallReq) returns (CallRsp) {
option (micro.openapiv2.openapiv2_operation) = {
operation_id: "Call";
responses: {
key: "default";
value: {
description: "Error response";
schema: {
json_schema: {
ref: ".example.Error";
}
}
}
}
};
option (micro.api.http) = { post: "/v1/example/call/{name}"; body: "*"; };
option (micro.api.micro_method) = { timeout: 5; };
};
};
message CallReq {
string name = 1 [(micro.tag.tags) = "xml:\",attr\"" ];
string req = 2;
};
message CallRsp {
string rsp = 2;
};
message Error {
string msg = 1;
};

10
go.mod
View File

@@ -1,10 +1,12 @@
module github.com/unistack-org/protoc-gen-micro/v3 module github.com/unistack-org/protoc-gen-go-micro/v3
go 1.16 go 1.16
require ( require (
github.com/google/go-cmp v0.5.4 // indirect github.com/fatih/structtag v1.2.0
github.com/unistack-org/micro-proto v0.0.1 github.com/unistack-org/micro-proto v0.0.2
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/protobuf v1.25.0 google.golang.org/protobuf v1.26.0
) )
//replace github.com/unistack-org/micro-proto => ../micro-proto

16
go.sum
View File

@@ -4,6 +4,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -14,18 +16,18 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
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=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/unistack-org/micro-proto v0.0.1 h1:1d9O8d3/ZITQPwIQCvZ+2OCDjVP0iaX+gv5klbwkE/I= github.com/unistack-org/micro-proto v0.0.2 h1:mL1ZPRGPCWJOiMBiJrkk8Y513rPrJmhJWxyLceckAXU=
github.com/unistack-org/micro-proto v0.0.1/go.mod h1:GYO53DWmeldRIo90cAdQx8bLr/WJMxW62W4ja74p1Ac= github.com/unistack-org/micro-proto v0.0.2/go.mod h1:GYO53DWmeldRIo90cAdQx8bLr/WJMxW62W4ja74p1Ac=
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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -65,7 +67,9 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -30,7 +30,8 @@ func (g *Generator) gorillaGenerate(component string, plugin *protogen.Plugin) e
} }
gfile := plugin.NewGeneratedFile(gname, path) gfile := plugin.NewGeneratedFile(gname, path)
gfile.P("// Code generated by protoc-gen-micro") gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.")
gfile.P("// protoc-gen-go-micro version: " + versionComment)
gfile.P("package ", file.GoPackageName) gfile.P("package ", file.GoPackageName)
gfile.P() gfile.P()

31
http.go
View File

@@ -4,7 +4,7 @@ import (
"google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/compiler/protogen"
) )
func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin) error { func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin, genClient bool, genServer bool) error {
for _, file := range plugin.Files { for _, file := range plugin.Files {
if !file.Generate { if !file.Generate {
continue continue
@@ -20,23 +20,32 @@ func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin) erro
} }
gfile := plugin.NewGeneratedFile(gname, path) gfile := plugin.NewGeneratedFile(gname, path)
gfile.P("// Code generated by protoc-gen-micro") gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.")
gfile.P("// source: ", *file.Proto.Name) gfile.P("// protoc-gen-go-micro version: " + versionComment)
gfile.P("// source: ", file.Proto.GetName())
gfile.P("package ", file.GoPackageName) gfile.P("package ", file.GoPackageName)
gfile.P() gfile.P()
gfile.Import(contextPackage) gfile.Import(contextPackage)
gfile.Import(microApiPackage) gfile.Import(microApiPackage)
gfile.Import(microClientPackage) if genClient {
gfile.Import(microClientHttpPackage) gfile.Import(microClientPackage)
gfile.Import(microServerPackage) gfile.Import(microClientHttpPackage)
}
if genServer {
gfile.Import(microServerPackage)
}
for _, service := range file.Services { for _, service := range file.Services {
generateServiceClient(gfile, service) if genClient {
generateServiceClientMethods(gfile, service, true) generateServiceClient(gfile, service)
generateServiceServer(gfile, service) generateServiceClientMethods(gfile, service, true)
generateServiceServerMethods(gfile, service) }
generateServiceRegister(gfile, service) if genServer {
generateServiceServer(gfile, service)
generateServiceServerMethods(gfile, service)
generateServiceRegister(gfile, service)
}
} }
} }

34
main.go
View File

@@ -12,7 +12,8 @@ import (
var ( var (
flagDebug = flag.Bool("debug", false, "") flagDebug = flag.Bool("debug", false, "")
flagStandalone = flag.Bool("standalone", false, "") flagStandalone = flag.Bool("standalone", false, "")
flagComponents = flag.String("components", "micro|rpc", "") flagComponents = flag.String("components", "micro|rpc|http|client|server", "")
flagTagPath = flag.String("tag_path", "", "")
) )
func main() { func main() {
@@ -29,6 +30,7 @@ type Generator struct {
components string components string
standalone bool standalone bool
debug bool debug bool
tagPath string
} }
func (g *Generator) Generate(plugin *protogen.Plugin) error { func (g *Generator) Generate(plugin *protogen.Plugin) error {
@@ -37,17 +39,36 @@ func (g *Generator) Generate(plugin *protogen.Plugin) error {
g.standalone = *flagStandalone g.standalone = *flagStandalone
g.debug = *flagDebug g.debug = *flagDebug
g.components = *flagComponents g.components = *flagComponents
g.tagPath = *flagTagPath
plugin.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL) plugin.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)
var genClient bool
var genServer bool
if strings.Contains(g.components, "server") {
genServer = true
}
if strings.Contains(g.components, "client") {
genClient = true
}
if strings.Contains(g.components, "rpc") || strings.Contains(g.components, "http") {
if !genServer && !genClient {
genServer = true
genClient = true
}
}
// Protoc passes a slice of File structs for us to process // Protoc passes a slice of File structs for us to process
for _, component := range strings.Split(g.components, "|") { for _, component := range strings.Split(g.components, "|") {
switch component { switch component {
case "server", "client":
continue
case "micro": case "micro":
err = g.microGenerate(component, plugin) err = g.microGenerate(component, plugin, genClient, genServer)
case "http": case "http":
err = g.httpGenerate(component, plugin) err = g.httpGenerate(component, plugin, genClient, genServer)
case "grpc", "rpc": case "grpc", "rpc":
err = g.rpcGenerate("rpc", plugin) err = g.rpcGenerate("rpc", plugin, genClient, genServer)
case "gorilla": case "gorilla":
err = g.gorillaGenerate(component, plugin) err = g.gorillaGenerate(component, plugin)
case "chi": case "chi":
@@ -63,5 +84,10 @@ func (g *Generator) Generate(plugin *protogen.Plugin) error {
} }
if err = g.astGenerate(plugin); err != nil {
plugin.Error(err)
return err
}
return nil return nil
} }

View File

@@ -4,7 +4,7 @@ import (
"google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/compiler/protogen"
) )
func (g *Generator) microGenerate(component string, plugin *protogen.Plugin) error { func (g *Generator) microGenerate(component string, plugin *protogen.Plugin, genClient bool, genServer bool) error {
for _, file := range plugin.Files { for _, file := range plugin.Files {
if !file.Generate { if !file.Generate {
continue continue
@@ -21,22 +21,28 @@ func (g *Generator) microGenerate(component string, plugin *protogen.Plugin) err
} }
gfile := plugin.NewGeneratedFile(gname, path) gfile := plugin.NewGeneratedFile(gname, path)
gfile.P("// Code generated by protoc-gen-micro") gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.")
gfile.P("// source: ", *file.Proto.Name) gfile.P("// protoc-gen-go-micro version: " + versionComment)
gfile.P("// source: ", file.Proto.GetName())
gfile.P("package ", file.GoPackageName) gfile.P("package ", file.GoPackageName)
gfile.P() gfile.P()
gfile.Import(contextPackage) gfile.Import(contextPackage)
gfile.Import(microApiPackage) gfile.Import(microApiPackage)
gfile.Import(microClientPackage) if genClient {
gfile.Import(microClientPackage)
}
// generate services // generate services
for _, service := range file.Services { for _, service := range file.Services {
generateServiceEndpoints(gfile, service) generateServiceEndpoints(gfile, service)
generateServiceClientInterface(gfile, service) if genClient {
generateServiceClientStreamInterface(gfile, service) generateServiceClientInterface(gfile, service)
generateServiceServerInterface(gfile, service) generateServiceClientStreamInterface(gfile, service)
generateServiceServerStreamInterface(gfile, service) }
if genServer {
generateServiceServerInterface(gfile, service)
generateServiceServerStreamInterface(gfile, service)
}
} }
} }

30
rpc.go
View File

@@ -4,7 +4,7 @@ import (
"google.golang.org/protobuf/compiler/protogen" "google.golang.org/protobuf/compiler/protogen"
) )
func (g *Generator) rpcGenerate(component string, plugin *protogen.Plugin) error { func (g *Generator) rpcGenerate(component string, plugin *protogen.Plugin, genClient bool, genServer bool) error {
for _, file := range plugin.Files { for _, file := range plugin.Files {
if !file.Generate { if !file.Generate {
continue continue
@@ -20,22 +20,30 @@ func (g *Generator) rpcGenerate(component string, plugin *protogen.Plugin) error
} }
gfile := plugin.NewGeneratedFile(gname, path) gfile := plugin.NewGeneratedFile(gname, path)
gfile.P("// Code generated by protoc-gen-micro") gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.")
gfile.P("// source: ", *file.Proto.Name) gfile.P("// protoc-gen-go-micro version: " + versionComment)
gfile.P("// source: ", file.Proto.GetName())
gfile.P("package ", file.GoPackageName) gfile.P("package ", file.GoPackageName)
gfile.P() gfile.P()
gfile.Import(contextPackage) gfile.Import(contextPackage)
gfile.Import(microApiPackage) gfile.Import(microApiPackage)
gfile.Import(microClientPackage) if genClient {
gfile.Import(microServerPackage) gfile.Import(microClientPackage)
}
if genServer {
gfile.Import(microServerPackage)
}
for _, service := range file.Services { for _, service := range file.Services {
generateServiceClient(gfile, service) if genClient {
generateServiceClientMethods(gfile, service, false) generateServiceClient(gfile, service)
generateServiceServer(gfile, service) generateServiceClientMethods(gfile, service, false)
generateServiceServerMethods(gfile, service) }
generateServiceRegister(gfile, service) if genServer {
generateServiceServer(gfile, service)
generateServiceServerMethods(gfile, service)
generateServiceRegister(gfile, service)
}
} }
} }

105
util.go
View File

@@ -11,19 +11,17 @@ import (
) )
var ( var (
reflectPackage = protogen.GoImportPath("reflect") httpMethodMap = map[string]string{
stringsPackage = protogen.GoImportPath("strings") "GET": "MethodGet",
fmtPackage = protogen.GoImportPath("fmt") "HEAD": "MethodHead",
contextPackage = protogen.GoImportPath("context") "POST": "MethodPost",
httpPackage = protogen.GoImportPath("net/http") "PUT": "MethodPut",
gorillaMuxPackage = protogen.GoImportPath("github.com/gorilla/mux") "PATCH": "MethodPatch",
chiPackage = protogen.GoImportPath("github.com/go-chi/chi/v4") "DELETE": "MethodDelete",
chiMiddlewarePackage = protogen.GoImportPath("github.com/go-chi/chi/v4/middleware") "CONNECT": "MethodConnect",
microApiPackage = protogen.GoImportPath("github.com/unistack-org/micro/v3/api") "OPTIONS": "MethodOptions",
microClientPackage = protogen.GoImportPath("github.com/unistack-org/micro/v3/client") "TRACE": "MethodTrace",
microServerPackage = protogen.GoImportPath("github.com/unistack-org/micro/v3/server") }
microClientHttpPackage = protogen.GoImportPath("github.com/unistack-org/micro-client-http/v3")
deprecationComment = "// Deprecated: Do not use."
) )
func unexport(s string) string { func unexport(s string) string {
@@ -32,6 +30,9 @@ func unexport(s string) string {
func generateServiceClient(gfile *protogen.GeneratedFile, service *protogen.Service) { func generateServiceClient(gfile *protogen.GeneratedFile, service *protogen.Service) {
serviceName := service.GoName serviceName := service.GoName
//if rule, ok := getMicroApiService(service); ok {
// gfile.P("// client wrappers ", strings.Join(rule.ClientWrappers, ", "))
// }
gfile.P("type ", unexport(serviceName), "Client struct {") gfile.P("type ", unexport(serviceName), "Client struct {")
gfile.P("c ", microClientPackage.Ident("Client")) gfile.P("c ", microClientPackage.Ident("Client"))
gfile.P("name string") gfile.P("name string")
@@ -68,18 +69,29 @@ func generateServiceClientMethods(gfile *protogen.GeneratedFile, service *protog
gfile.P("opts = append(opts,") gfile.P("opts = append(opts,")
gfile.P(microClientHttpPackage.Ident("ErrorMap"), "(errmap),") gfile.P(microClientHttpPackage.Ident("ErrorMap"), "(errmap),")
gfile.P(")")
if proto.HasExtension(method.Desc.Options(), api_options.E_Http) { }
endpoints, _ := generateEndpoints(method) if proto.HasExtension(method.Desc.Options(), api_options.E_Http) {
path, method, body := getEndpoint(endpoints[0]) gfile.P("opts = append(opts,")
endpoints, _ := generateEndpoints(method)
path, method, body := getEndpoint(endpoints[0])
if vmethod, ok := httpMethodMap[method]; ok {
gfile.P(microClientHttpPackage.Ident("Method"), `(`, httpPackage.Ident(vmethod), `),`)
} else {
gfile.P(microClientHttpPackage.Ident("Method"), `("`, method, `"),`) gfile.P(microClientHttpPackage.Ident("Method"), `("`, method, `"),`)
gfile.P(microClientHttpPackage.Ident("Path"), `("`, path, `"),`) }
gfile.P(microClientHttpPackage.Ident("Path"), `("`, path, `"),`)
if body != "" {
gfile.P(microClientHttpPackage.Ident("Body"), `("`, body, `"),`) gfile.P(microClientHttpPackage.Ident("Body"), `("`, body, `"),`)
} }
gfile.P(")") gfile.P(")")
} }
} }
if rule, ok := getMicroApiMethod(method); ok {
if rule.Timeout > 0 {
gfile.P("opts = append(opts, ", microClientPackage.Ident("WithRequestTimeout"), "(", timePackage.Ident("Second"), "*", rule.Timeout, "))")
}
}
if !method.Desc.IsStreamingServer() && !method.Desc.IsStreamingClient() { if !method.Desc.IsStreamingServer() && !method.Desc.IsStreamingClient() {
gfile.P("rsp := &", gfile.QualifiedGoIdent(method.Output.GoIdent), "{}") gfile.P("rsp := &", gfile.QualifiedGoIdent(method.Output.GoIdent), "{}")
@@ -177,7 +189,13 @@ func generateServiceServerMethods(gfile *protogen.GeneratedFile, service *protog
serviceName := service.GoName serviceName := service.GoName
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.Timeout > 0 {
gfile.P("var cancel ", contextPackage.Ident("CancelFunc"))
gfile.P("ctx, cancel = ", contextPackage.Ident("WithTimeout"), "(ctx, ", timePackage.Ident("Second"), "*", rule.Timeout, ")")
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), "{}")
@@ -265,10 +283,11 @@ func generateServiceRegister(gfile *protogen.GeneratedFile, service *protogen.Se
gfile.P(unexport(serviceName)) gfile.P(unexport(serviceName))
gfile.P("}") gfile.P("}")
gfile.P("h := &", unexport(serviceName), "Server{sh}") gfile.P("h := &", unexport(serviceName), "Server{sh}")
gfile.P("var nopts []", microServerPackage.Ident("HandlerOption"))
gfile.P("for _, endpoint := range New", serviceName, "Endpoints() {") gfile.P("for _, endpoint := range New", serviceName, "Endpoints() {")
gfile.P("opts = append(opts, ", microApiPackage.Ident("WithEndpoint"), "(endpoint))") gfile.P("nopts = append(nopts, ", microApiPackage.Ident("WithEndpoint"), "(endpoint))")
gfile.P("}") gfile.P("}")
gfile.P("return s.Handle(s.NewHandler(&", serviceName, "{h}, opts...))") gfile.P("return s.Handle(s.NewHandler(&", serviceName, "{h}, append(nopts, opts...)...))")
gfile.P("}") gfile.P("}")
} }
@@ -470,6 +489,42 @@ func generateEndpoints(method *protogen.Method) ([]*api_options.HttpRule, bool)
return rules, method.Desc.IsStreamingServer() || method.Desc.IsStreamingClient() return rules, method.Desc.IsStreamingServer() || method.Desc.IsStreamingClient()
} }
func getMicroApiMethod(method *protogen.Method) (*api_options.MicroMethod, bool) {
if method.Desc.Options() == nil {
return nil, false
}
if !proto.HasExtension(method.Desc.Options(), api_options.E_MicroMethod) {
return nil, false
}
r := proto.GetExtension(method.Desc.Options(), api_options.E_MicroMethod)
if r == nil {
return nil, false
}
rule := r.(*api_options.MicroMethod)
return rule, true
}
func getMicroApiService(service *protogen.Service) (*api_options.MicroService, bool) {
if service.Desc.Options() == nil {
return nil, false
}
if !proto.HasExtension(service.Desc.Options(), api_options.E_MicroService) {
return nil, false
}
r := proto.GetExtension(service.Desc.Options(), api_options.E_MicroService)
if r == nil {
return nil, false
}
rule := r.(*api_options.MicroService)
return rule, true
}
func getEndpoint(rule *api_options.HttpRule) (string, string, string) { func getEndpoint(rule *api_options.HttpRule) (string, string, string) {
var meth string var meth string
var path string var path string
@@ -505,8 +560,12 @@ func generateEndpoint(gfile *protogen.GeneratedFile, serviceName string, methodN
path, meth, body := getEndpoint(rule) path, meth, body := getEndpoint(rule)
gfile.P("Name:", fmt.Sprintf(`"%s.%s",`, serviceName, methodName)) gfile.P("Name:", fmt.Sprintf(`"%s.%s",`, serviceName, methodName))
gfile.P("Path:", fmt.Sprintf(`[]string{"%s"},`, path)) gfile.P("Path:", fmt.Sprintf(`[]string{"%s"},`, path))
//if vmethod, ok := httpMethodMap[meth]; ok {
// gfile.P("Method:", `[]string{`, httpPackage.Ident(vmethod), `},`)
//} else {
gfile.P("Method:", fmt.Sprintf(`[]string{"%s"},`, meth)) gfile.P("Method:", fmt.Sprintf(`[]string{"%s"},`, meth))
if len(rule.GetGet()) == 0 { // }
if len(rule.GetGet()) == 0 && body != "" {
gfile.P("Body:", fmt.Sprintf(`"%s",`, body)) gfile.P("Body:", fmt.Sprintf(`"%s",`, body))
} }
if streaming { if streaming {

21
variables.go Normal file
View File

@@ -0,0 +1,21 @@
package main
import "google.golang.org/protobuf/compiler/protogen"
var (
reflectPackage = protogen.GoImportPath("reflect")
stringsPackage = protogen.GoImportPath("strings")
fmtPackage = protogen.GoImportPath("fmt")
contextPackage = protogen.GoImportPath("context")
httpPackage = protogen.GoImportPath("net/http")
gorillaMuxPackage = protogen.GoImportPath("github.com/gorilla/mux")
chiPackage = protogen.GoImportPath("github.com/go-chi/chi/v5")
chiMiddlewarePackage = protogen.GoImportPath("github.com/go-chi/chi/v5/middleware")
microApiPackage = protogen.GoImportPath("github.com/unistack-org/micro/v3/api")
microClientPackage = protogen.GoImportPath("github.com/unistack-org/micro/v3/client")
microServerPackage = protogen.GoImportPath("github.com/unistack-org/micro/v3/server")
microClientHttpPackage = protogen.GoImportPath("github.com/unistack-org/micro-client-http/v3")
timePackage = protogen.GoImportPath("time")
deprecationComment = "// Deprecated: Do not use."
versionComment = "v3.4.0"
)