Skip to content

Commit

Permalink
feat: support thrift reflection (#106)
Browse files Browse the repository at this point in the history
  • Loading branch information
HeyJavaBean authored Jul 24, 2023
1 parent 38197be commit 10bdd23
Show file tree
Hide file tree
Showing 24 changed files with 14,021 additions and 26 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/push-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Unit Test
run: go test -v -race -covermode=atomic -coverprofile=coverage.out ./...

- name: Lint
run: |
go install mvdan.cc/[email protected]
test -z "$(gofumpt -l -extra .)"
go vet -stdmethods=false $(go list ./...)
- name: Unit Test
run: go test -v -race -covermode=atomic -coverprofile=coverage.out ./...
go vet -stdmethods=false $(go list ./...)
137 changes: 137 additions & 0 deletions descriptor.thrift
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright 2023 CloudWeGo Authors
//
// 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.

namespace go thrift_reflection

struct TypeDescriptor{
1:required string filepath // the name of idl file
2:required string name
3:optional TypeDescriptor key_type // key type for map container
4:optional TypeDescriptor value_type // value type for map container, or the type for list and set
5:optional map<string,string> extra // extra info
}

struct ConstDescriptor{
1:required string filepath // the name of idl file
2:required string name
3:required TypeDescriptor type
4:required ConstValueDescriptor value
5:required map<string,list<string>> annotations
6:required string comments
7:optional map<string,string> extra // extra info
}

enum ConstValueType{
DOUBLE
INT
STRING
BOOL
LIST
MAP
IDENTIFIER
}

struct ConstValueDescriptor{
1:required ConstValueType type
2:required double value_double // for double
3:required i64 value_int // for i8 i16 i32 i64 byte binary
4:required string value_string // for string
5:required bool value_bool // for bool
6:optional list<ConstValueDescriptor> value_list // for list set
7:optional map<ConstValueDescriptor,ConstValueDescriptor> value_map // for map
8:required string value_identifier // for identifier, such as another constant's name
}

struct TypedefDescriptor{
1:required string filepath // the name of idl file
2:required TypeDescriptor type
3:required string alias
4:required map<string,list<string>> annotations
5:required string comments
6:optional map<string,string> extra // extra
}

struct EnumDescriptor{
1:required string filepath // the name of idl file
2:required string name
3:required list<EnumValueDescriptor> values
4:required map<string,list<string>> annotations
5:required string comments
6:optional map<string,string> extra // extra info
}

struct EnumValueDescriptor{
1:required string filepath // the name of idl file
2:required string name
3:required i64 value
4:required map<string,list<string>> annotations
5:required string comments
6:optional map<string,string> extra // extra info
}

struct FieldDescriptor{
1:required string filepath // the name of idl file
2:required string name
3:required TypeDescriptor type
4:required string requiredness // required, optional, or default
5:required i32 id // field id
6:optional ConstValueDescriptor default_value
7:required map<string,list<string>> annotations
8:required string comments
9:optional map<string,string> extra // extra info
}

struct StructDescriptor{
1:required string filepath // the name of idl file
2:required string name
3:required list<FieldDescriptor> fields
4:required map<string,list<string>> annotations
5:required string comments
6:optional map<string,string> extra // extra info
}

struct MethodDescriptor{
1:required string filepath // the name of idl file
2:required string name
3:optional TypeDescriptor response // response, if it's oneway method, this should be nil
4:required list<FieldDescriptor> args
5:required map<string,list<string>> annotations
6:required string comments
7:required list<FieldDescriptor> throw_exceptions
8:required bool is_oneway
9:optional map<string,string> extra // extra info
}

struct ServiceDescriptor{
1:required string filepath // the name of idl file
2:required string name
3:required list<MethodDescriptor> methods
4:required map<string,list<string>> annotations
5:required string comments
6:optional map<string,string> extra // extra info
}

struct FileDescriptor{
1:required string filepath // the path of idl file, eg: xx/idl/entity.thrift
2:required map<string,string> includes // include IDL, key is alias and value is filepath, eg: entity -> xx/idl/entity.thrift
3:required map<string,string> namespaces // namespace, key is language and value is namespace for this language, eg: go -> xxx ; java -> xxx
4:required list<ServiceDescriptor> services
5:required list<StructDescriptor> structs
6:required list<StructDescriptor> exceptions
7:required list<EnumDescriptor> enums
8:required list<TypedefDescriptor> typedefs
9:required list<StructDescriptor> unions
10:required list<ConstDescriptor> consts
11:optional map<string,string> extra // extra info
}
15 changes: 15 additions & 0 deletions descriptor_code_gen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2023 CloudWeGo Authors
#
# 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.

go run . -g go:gen_type_meta -o . descriptor.thrift
21 changes: 11 additions & 10 deletions generator/golang/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,17 @@ func (im *importManager) init(cu *CodeUtils, ast *parser.Thrift) {
ns := im.Namespace

std := map[string]string{
"context": "context",
"fmt": "fmt",
"driver": "database/sql/driver",
"sql": "database/sql",
"strings": "strings",
"bytes": "bytes",
"reflect": "reflect",
"thrift": DefaultThriftLib,
"unknown": DefaultUnknownLib,
"meta": DefaultMetaLib,
"context": "context",
"fmt": "fmt",
"driver": "database/sql/driver",
"sql": "database/sql",
"strings": "strings",
"bytes": "bytes",
"reflect": "reflect",
"thrift": DefaultThriftLib,
"unknown": DefaultUnknownLib,
"meta": DefaultMetaLib,
"thrift_reflection": ThriftReflectionLib,
}
for pkg, path := range std {
ns.Add(pkg, path)
Expand Down
2 changes: 1 addition & 1 deletion generator/golang/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func prettifyBytesLiteral(s string) string {
rs = append(rs, r)
if r == ',' {
cnt++
if cnt == 8 {
if cnt == 16 {
rs = append(rs, '\n')
cnt = 0
}
Expand Down
3 changes: 2 additions & 1 deletion generator/golang/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ type Features struct {
AlwaysGenerateJSONTag bool `always_gen_json_tag:"Always generate 'json' tag even if go.tag is provided (Disabled by default)"`
SnakeTyleJSONTag bool `snake_style_json_tag:"Generate snake style json tag"`
LowerCamelCaseJSONTag bool `lower_camel_style_json_tag:"Generate lower camel case style json tag"`
GenerateReflectionInfo bool `generate_reflection_info:"Generate reflection info json"`
GenerateReflectionInfo bool `generate_reflection_info:"This option is no longer used. Please use with_reflection instead."`
WithReflection bool `with_reflection:"Generate reflection info"`
EnumAsINT32 bool `enum_as_int_32:"Generate enum type as int32"`
}

Expand Down
12 changes: 10 additions & 2 deletions generator/golang/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import (
"path/filepath"
"strings"

"github.com/cloudwego/thriftgo/reflection"

"github.com/cloudwego/thriftgo/parser"
"github.com/cloudwego/thriftgo/pkg/namespace"
"github.com/cloudwego/thriftgo/reflection"
"github.com/cloudwego/thriftgo/thrift_reflection"
)

// Name is the type of identifiers converted from a thrift AST to Go code.
Expand Down Expand Up @@ -140,6 +140,14 @@ func (s *Scope) IDLName() string {
return idlName
}

func (s *Scope) MarshalDescriptor() string {
bytes, err := thrift_reflection.GetFileDescriptor(s.ast).Marshal()
if err != nil {
return fmt.Sprintf("[]byte{} // ERROR: Marshal descriptor failed: %s", err.Error())
}
return prettifyBytesLiteral(fmt.Sprintf("%#v", bytes))
}

func (s *Scope) RefPath() string {
return s.refPath
}
Expand Down
79 changes: 79 additions & 0 deletions generator/golang/templates/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,84 @@ import (
thriftreflection.RegisterIDL(file_{{.IDLName}}_rawDesc)
}
{{end}}
{{- if Features.WithReflection}}
{{- UseStdLibrary "thrift_reflection"}}
{{$IDLName := .IDLName}}
{{$IDLPath := .AST.Filename}}
{{$FilePackage := .FilePackage}}
var file_{{$IDLName}}_thrift_go_types = []interface{}{
{{- range $index, $element := .Structs}}
(*{{.GoName}})(nil), // Struct {{$index}}: {{$FilePackage}}.{{.Name}}
{{- end}}
{{- range $index, $element := .Unions}}
(*{{.GoName}})(nil), // Union {{$index}}: {{$FilePackage}}.{{.Name}}
{{- end}}
{{- range $index, $element := .Exceptions}}
(*{{.GoName}})(nil), // Exception {{$index}}: {{$FilePackage}}.{{.Name}}
{{- end}}
{{- range $index, $element := .Enums}}
(*{{.GoName}})(nil), // Enum {{$index}}: {{$FilePackage}}.{{.Name}}
{{- end}}
}
var file_{{$IDLName}}_thrift *thrift_reflection.FileDescriptor
var file_idl_{{$IDLName}}_rawDesc = {{.MarshalDescriptor}}
func init() {
if file_{{$IDLName}}_thrift != nil {
return
}
file_{{$IDLName}}_thrift = thrift_reflection.BuildFileDescriptor(file_idl_{{$IDLName}}_rawDesc,file_{{$IDLName}}_thrift_go_types)
}
func GetFileDescriptorFor{{ToCamel $IDLName}}() *thrift_reflection.FileDescriptor{
return file_{{$IDLName}}_thrift
}
{{- range .Structs}}
func (p *{{.GoName}}) GetDescriptor() *thrift_reflection.StructDescriptor{
return file_{{$IDLName}}_thrift.GetStructDescriptor("{{.Name}}")
}
{{- end}}
{{- range .Enums}}
func (p {{.GoName}}) GetDescriptor() *thrift_reflection.EnumDescriptor{
return file_{{$IDLName}}_thrift.GetEnumDescriptor("{{.Name}}")
}
{{- end}}
{{- range .Typedefs}}
func GetTypeDescriptorFor{{.GoName}}() *thrift_reflection.TypedefDescriptor{
return file_{{$IDLName}}_thrift.GetTypedefDescriptor("{{.Alias}}")
}
{{- end}}
{{- range .Constants.GoConstants}}
func GetConstDescriptorFor{{.GoName}}() *thrift_reflection.ConstDescriptor{
return file_{{$IDLName}}_thrift.GetConstDescriptor("{{.Name}}")
}
{{- end}}
{{- range .Unions}}
func (p *{{.GoName}}) GetDescriptor() *thrift_reflection.StructDescriptor{
return file_{{$IDLName}}_thrift.GetUnionDescriptor("{{.Name}}")
}
{{- end}}
{{- range .Exceptions}}
func (p *{{.GoName}}) GetDescriptor() *thrift_reflection.StructDescriptor{
return file_{{$IDLName}}_thrift.GetExceptionDescriptor("{{.Name}}")
}
{{- end}}
{{- range .Services}}
{{$ServiceName := .GoName}}
func GetServiceDescriptorFor{{.GoName}}() *thrift_reflection.ServiceDescriptor{
return file_{{$IDLName}}_thrift.GetServiceDescriptor("{{.Name}}")
}
{{- range .Functions}}
func GetMethodDescriptorFor{{$ServiceName}}{{.GoName}}() *thrift_reflection.MethodDescriptor{
return file_{{$IDLName}}_thrift.GetMethodDescriptor("{{$ServiceName}}","{{.Name}}")
}
{{- end}}
{{- end}}
{{end}}
{{- InsertionPoint "eof"}}
`
19 changes: 13 additions & 6 deletions generator/golang/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ import (

// Default libraries.
const (
DefaultThriftLib = "github.com/apache/thrift/lib/go/thrift"
DefaultUnknownLib = "github.com/cloudwego/thriftgo/generator/golang/extension/unknown"
DefaultMetaLib = "github.com/cloudwego/thriftgo/generator/golang/extension/meta"
defaultTemplate = "default"
DefaultThriftLib = "github.com/apache/thrift/lib/go/thrift"
DefaultUnknownLib = "github.com/cloudwego/thriftgo/generator/golang/extension/unknown"
DefaultMetaLib = "github.com/cloudwego/thriftgo/generator/golang/extension/meta"
ThriftReflectionLib = "github.com/cloudwego/thriftgo/thrift_reflection"
ThriftOptionLib = "github.com/cloudwego/thriftgo/option"
defaultTemplate = "default"
)

var escape = regexp.MustCompile(`\\.`)
Expand Down Expand Up @@ -357,8 +359,13 @@ func (cu *CodeUtils) RootScope() *Scope {
// BuildFuncMap builds a function map for templates.
func (cu *CodeUtils) BuildFuncMap() template.FuncMap {
m := map[string]interface{}{
"ToUpper": strings.ToUpper,
"ToLower": strings.ToLower,
"ToUpper": strings.ToUpper,
"ToLower": strings.ToLower,
"ToCamel": func(name string) string {
name = strings.Replace(name, "_", " ", -1)
name = strings.Title(name)
return strings.Replace(name, " ", "", -1)
},
"InsertionPoint": plugin.InsertionPoint,
"Unexport": common.Unexport,

Expand Down
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/cloudwego/thriftgo

go 1.13

require golang.org/x/text v0.6.0
require (
github.com/apache/thrift v0.13.0
golang.org/x/text v0.6.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/apache/thrift v0.13.0 h1:5hryIiq9gtn+MiLVn0wP37kb/uTeRZgN08WoCsAhIhI=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
)

// Version of thriftgo.
const Version = "0.2.12"
const Version = "0.3.0"

var (
a Arguments
Expand Down
Loading

0 comments on commit 10bdd23

Please sign in to comment.