Skip to content

Commit

Permalink
feat(generic): add an option to specify an IDL service name to be par…
Browse files Browse the repository at this point in the history
…sed (#1673)
  • Loading branch information
Marina-Sakai authored Jan 15, 2025
1 parent 2f49a5f commit b7777a2
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 64 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/bytedance/gopkg v0.1.1
github.com/bytedance/sonic v1.12.7
github.com/cloudwego/configmanager v0.2.2
github.com/cloudwego/dynamicgo v0.5.0
github.com/cloudwego/dynamicgo v0.5.1-0.20250115031329-d58b94fc7d71
github.com/cloudwego/fastpb v0.0.5
github.com/cloudwego/frugal v0.2.3
github.com/cloudwego/gopkg v0.1.4-0.20241217093255-8980b14172b7
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/configmanager v0.2.2 h1:sVrJB8gWYTlPV2OS3wcgJSO9F2/9Zbkmcm1Z7jempOU=
github.com/cloudwego/configmanager v0.2.2/go.mod h1:ppiyU+5TPLonE8qMVi/pFQk2eL3Q4P7d4hbiNJn6jwI=
github.com/cloudwego/dynamicgo v0.5.0 h1:wcmeZIRC6iW/36sId16ktIFvgnyKER9VzhjEsNhw2GU=
github.com/cloudwego/dynamicgo v0.5.0/go.mod h1:DknfxjIMuGvXow409bS/AWycXONdc02HECBL0qpNqTY=
github.com/cloudwego/dynamicgo v0.5.1-0.20250115031329-d58b94fc7d71 h1:J57+W8YYGJy0MCLk/yzuLehiQmKpOoQng+OBF/5204o=
github.com/cloudwego/dynamicgo v0.5.1-0.20250115031329-d58b94fc7d71/go.mod h1:DknfxjIMuGvXow409bS/AWycXONdc02HECBL0qpNqTY=
github.com/cloudwego/fastpb v0.0.5 h1:vYnBPsfbAtU5TVz5+f9UTlmSCixG9F9vRwaqE0mZPZU=
github.com/cloudwego/fastpb v0.0.5/go.mod h1:Bho7aAKBUtT9RPD2cNVkTdx4yQumfSv3If7wYnm1izk=
github.com/cloudwego/frugal v0.2.3 h1:t1hhhAi8lXcx7Ncs4PR1pSZ90vlDU1cy5K2btDMFpoA=
Expand Down
46 changes: 33 additions & 13 deletions pkg/generic/thrift/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,33 @@ func Parse(tree *parser.Thrift, mode ParseMode, opts ...ParseOption) (*descripto
Router: descriptor.NewRouter(),
}

pOpts := &parseOptions{}
pOpts.apply(opts)

// support one service
svcs := tree.Services
switch mode {
case LastServiceOnly:
svcs = svcs[len(svcs)-1:]
sDsc.Name = svcs[len(svcs)-1].Name
case FirstServiceOnly:
svcs = svcs[:1]
sDsc.Name = svcs[0].Name
case CombineServices:
sDsc.Name = "CombinedServices"
sDsc.IsCombinedServices = true
}

pOpts := &parseOptions{}
pOpts.apply(opts)
// if an idl service name is specified, it takes precedence over parse mode
if pOpts.serviceName != "" {
var err error
svcs, err = getTargetService(svcs, pOpts.serviceName)
if err != nil {
return nil, err
}
sDsc.Name = pOpts.serviceName
} else {
switch mode {
case LastServiceOnly:
svcs = svcs[len(svcs)-1:]
sDsc.Name = svcs[len(svcs)-1].Name
case FirstServiceOnly:
svcs = svcs[:1]
sDsc.Name = svcs[0].Name
case CombineServices:
sDsc.Name = "CombinedServices"
sDsc.IsCombinedServices = true
}
}

visitedSvcs := make(map[*parser.Service]bool, len(tree.Services))
for _, svc := range svcs {
Expand All @@ -109,6 +120,15 @@ func Parse(tree *parser.Thrift, mode ParseMode, opts ...ParseOption) (*descripto
return sDsc, nil
}

func getTargetService(svcs []*parser.Service, serviceName string) ([]*parser.Service, error) {
for _, svc := range svcs {
if svc.Name == serviceName {
return []*parser.Service{svc}, nil
}
}
return nil, fmt.Errorf("the idl service name %s is not in the idl. Please check your idl", serviceName)
}

type pair struct {
tree *parser.Thrift
data interface{}
Expand Down
11 changes: 10 additions & 1 deletion pkg/generic/thrift/parse_option.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ package thrift
import "github.com/cloudwego/kitex/pkg/generic/descriptor"

type parseOptions struct {
goTag *descriptor.GoTagOption
goTag *descriptor.GoTagOption
serviceName string
}

type ParseOption struct {
Expand All @@ -39,3 +40,11 @@ func WithGoTagDisabled(disable bool) ParseOption {
}
}}
}

// WithIDLServiceName specifies the target IDL service to be parsed.
// NOTE: with this option, the specified service is prioritized and parse mode will be ignored.
func WithIDLServiceName(serviceName string) ParseOption {
return ParseOption{F: func(opt *parseOptions) {
opt.serviceName = serviceName
}}
}
15 changes: 15 additions & 0 deletions pkg/generic/thrift/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,3 +510,18 @@ func defaultValueDeepEqual(t *testing.T, defaultValue func(name string) interfac
"a": int32(56),
}))
}

func TestParseWithIDLServiceName(t *testing.T) {
demo, err := parser.ParseString("demo.thrift", demoIDL)
test.Assert(t, err == nil)

base, err := parser.ParseString("base.thrift", baseIDL)
test.Assert(t, err == nil)

demo.Includes[0].Reference = base

sDsc, err := Parse(demo, LastServiceOnly, WithIDLServiceName("DemoBaseService"))
test.Assert(t, err == nil)
// priority: service name specification > parse mode
test.Assert(t, sDsc.Name == "DemoBaseService")
}
108 changes: 63 additions & 45 deletions pkg/generic/thriftidl_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func NewThriftFileProviderWithOption(path string, opts []ThriftIDLProviderOption
}
tOpts := &thriftIDLProviderOptions{}
tOpts.apply(opts)
svc, err := newServiceDescriptorFromPath(path, getParseMode(tOpts), tOpts.goTag, includeDirs...)
svc, err := newServiceDescriptorFromPath(path, getParseMode(tOpts), tOpts.goTag, tOpts.serviceName, includeDirs...)
if err != nil {
return nil, err
}
Expand All @@ -79,7 +79,7 @@ func NewThriftFileProviderWithDynamicgoWithOption(path string, opts []ThriftIDLP
tOpts := &thriftIDLProviderOptions{}
tOpts.apply(opts)
parseMode := getParseMode(tOpts)
svc, err := newServiceDescriptorFromPath(path, parseMode, tOpts.goTag, includeDirs...)
svc, err := newServiceDescriptorFromPath(path, parseMode, tOpts.goTag, tOpts.serviceName, includeDirs...)
if err != nil {
return nil, err
}
Expand All @@ -90,7 +90,7 @@ func NewThriftFileProviderWithDynamicgoWithOption(path string, opts []ThriftIDLP
return nil, err
}
handleGoTagForDynamicGo(tOpts.goTag)
dOpts := dthrift.Options{EnableThriftBase: true, ParseServiceMode: dParseMode, UseDefaultValue: true, SetOptionalBitmap: true}
dOpts := dthrift.Options{EnableThriftBase: true, ParseServiceMode: dParseMode, UseDefaultValue: true, SetOptionalBitmap: true, ServiceName: tOpts.serviceName}
dsvc, err := dOpts.NewDescritorFromPath(context.Background(), path, includeDirs...)
if err != nil {
// fall back to the original way (without dynamicgo)
Expand All @@ -105,7 +105,7 @@ func NewThriftFileProviderWithDynamicgoWithOption(path string, opts []ThriftIDLP
return p, nil
}

func newServiceDescriptorFromPath(path string, parseMode thrift.ParseMode, goTagOpt *goTagOption, includeDirs ...string) (*descriptor.ServiceDescriptor, error) {
func newServiceDescriptorFromPath(path string, parseMode thrift.ParseMode, goTagOpt *goTagOption, serviceName string, includeDirs ...string) (*descriptor.ServiceDescriptor, error) {
tree, err := parser.ParseFile(path, includeDirs, true)
if err != nil {
return nil, err
Expand All @@ -114,6 +114,9 @@ func newServiceDescriptorFromPath(path string, parseMode thrift.ParseMode, goTag
if goTagOpt != nil {
parseOpts = append(parseOpts, thrift.WithGoTagDisabled(goTagOpt.isGoTagAliasDisabled))
}
if serviceName != "" {
parseOpts = append(parseOpts, thrift.WithIDLServiceName(serviceName))
}
svc, err := thrift.Parse(tree, parseMode, parseOpts...)
if err != nil {
return nil, err
Expand Down Expand Up @@ -143,11 +146,12 @@ func (p *thriftFileProvider) Option() ProviderOption {

// ThriftContentProvider provide descriptor from contents
type ThriftContentProvider struct {
closeOnce sync.Once
svcs chan *descriptor.ServiceDescriptor
opts *ProviderOption
parseMode thrift.ParseMode
goTagOpt *goTagOption
closeOnce sync.Once
svcs chan *descriptor.ServiceDescriptor
opts *ProviderOption
parseMode thrift.ParseMode
goTagOpt *goTagOption
serviceName string
}

var _ DescriptorProvider = (*ThriftContentProvider)(nil)
Expand All @@ -161,12 +165,13 @@ func NewThriftContentProvider(main string, includes map[string]string, opts ...T
parseMode := getParseMode(tOpts)

p := &ThriftContentProvider{
svcs: make(chan *descriptor.ServiceDescriptor, 1), // unblock with buffered channel
opts: &ProviderOption{DynamicGoEnabled: false},
parseMode: parseMode,
goTagOpt: tOpts.goTag,
svcs: make(chan *descriptor.ServiceDescriptor, 1), // unblock with buffered channel
opts: &ProviderOption{DynamicGoEnabled: false},
parseMode: parseMode,
goTagOpt: tOpts.goTag,
serviceName: tOpts.serviceName,
}
svc, err := newServiceDescriptorFromContent(defaultMainIDLPath, main, includes, false, parseMode, tOpts.goTag)
svc, err := newServiceDescriptorFromContent(defaultMainIDLPath, main, includes, false, parseMode, tOpts.goTag, tOpts.serviceName)
if err != nil {
return nil, err
}
Expand All @@ -182,18 +187,19 @@ func NewThriftContentProviderWithDynamicGo(main string, includes map[string]stri
parseMode := getParseMode(tOpts)

p := &ThriftContentProvider{
svcs: make(chan *descriptor.ServiceDescriptor, 1), // unblock with buffered channel
opts: &ProviderOption{DynamicGoEnabled: true},
parseMode: parseMode,
goTagOpt: tOpts.goTag,
svcs: make(chan *descriptor.ServiceDescriptor, 1), // unblock with buffered channel
opts: &ProviderOption{DynamicGoEnabled: true},
parseMode: parseMode,
goTagOpt: tOpts.goTag,
serviceName: tOpts.serviceName,
}

svc, err := newServiceDescriptorFromContent(defaultMainIDLPath, main, includes, false, parseMode, tOpts.goTag)
svc, err := newServiceDescriptorFromContent(defaultMainIDLPath, main, includes, false, parseMode, tOpts.goTag, tOpts.serviceName)
if err != nil {
return nil, err
}

p.newDynamicGoDsc(svc, defaultMainIDLPath, main, includes, parseMode, tOpts.goTag)
p.newDynamicGoDsc(svc, defaultMainIDLPath, main, includes, parseMode, tOpts.goTag, tOpts.serviceName)

p.svcs <- svc
return p, nil
Expand All @@ -210,13 +216,16 @@ func (p *ThriftContentProvider) UpdateIDL(main string, includes map[string]strin
if p.goTagOpt != nil {
parseOpts = append(parseOpts, thrift.WithGoTagDisabled(p.goTagOpt.isGoTagAliasDisabled))
}
if p.serviceName != "" {
parseOpts = append(parseOpts, thrift.WithIDLServiceName(p.serviceName))
}
svc, err = thrift.Parse(tree, p.parseMode, parseOpts...)
if err != nil {
return err
}

if p.opts.DynamicGoEnabled {
p.newDynamicGoDsc(svc, defaultMainIDLPath, main, includes, p.parseMode, p.goTagOpt)
p.newDynamicGoDsc(svc, defaultMainIDLPath, main, includes, p.parseMode, p.goTagOpt, p.serviceName)
}

select {
Expand Down Expand Up @@ -248,8 +257,8 @@ func (p *ThriftContentProvider) Option() ProviderOption {
return *p.opts
}

func (p *ThriftContentProvider) newDynamicGoDsc(svc *descriptor.ServiceDescriptor, path, content string, includes map[string]string, parseMode thrift.ParseMode, goTag *goTagOption) {
if err := newDynamicGoDscFromContent(svc, path, content, includes, false, parseMode, goTag); err != nil {
func (p *ThriftContentProvider) newDynamicGoDsc(svc *descriptor.ServiceDescriptor, path, content string, includes map[string]string, parseMode thrift.ParseMode, goTag *goTagOption, serviceName string) {
if err := newDynamicGoDscFromContent(svc, path, content, includes, false, parseMode, goTag, serviceName); err != nil {
p.opts.DynamicGoEnabled = false
}
}
Expand Down Expand Up @@ -313,11 +322,12 @@ func ParseContent(path, content string, includes map[string]string, isAbsInclude

// ThriftContentWithAbsIncludePathProvider ...
type ThriftContentWithAbsIncludePathProvider struct {
closeOnce sync.Once
svcs chan *descriptor.ServiceDescriptor
opts *ProviderOption
parseMode thrift.ParseMode
goTagOpt *goTagOption
closeOnce sync.Once
svcs chan *descriptor.ServiceDescriptor
opts *ProviderOption
parseMode thrift.ParseMode
goTagOpt *goTagOption
serviceName string
}

var _ DescriptorProvider = (*ThriftContentWithAbsIncludePathProvider)(nil)
Expand All @@ -329,17 +339,18 @@ func NewThriftContentWithAbsIncludePathProvider(mainIDLPath string, includes map
parseMode := getParseMode(tOpts)

p := &ThriftContentWithAbsIncludePathProvider{
svcs: make(chan *descriptor.ServiceDescriptor, 1), // unblock with buffered channel
opts: &ProviderOption{DynamicGoEnabled: false},
parseMode: parseMode,
goTagOpt: tOpts.goTag,
svcs: make(chan *descriptor.ServiceDescriptor, 1), // unblock with buffered channel
opts: &ProviderOption{DynamicGoEnabled: false},
parseMode: parseMode,
goTagOpt: tOpts.goTag,
serviceName: tOpts.serviceName,
}
mainIDLContent, ok := includes[mainIDLPath]
if !ok {
return nil, fmt.Errorf("miss main IDL content for main IDL path: %s", mainIDLPath)
}

svc, err := newServiceDescriptorFromContent(mainIDLPath, mainIDLContent, includes, true, parseMode, tOpts.goTag)
svc, err := newServiceDescriptorFromContent(mainIDLPath, mainIDLContent, includes, true, parseMode, tOpts.goTag, tOpts.serviceName)
if err != nil {
return nil, err
}
Expand All @@ -355,22 +366,23 @@ func NewThriftContentWithAbsIncludePathProviderWithDynamicGo(mainIDLPath string,
parseMode := getParseMode(tOpts)

p := &ThriftContentWithAbsIncludePathProvider{
svcs: make(chan *descriptor.ServiceDescriptor, 1), // unblock with buffered channel
opts: &ProviderOption{DynamicGoEnabled: true},
parseMode: parseMode,
goTagOpt: tOpts.goTag,
svcs: make(chan *descriptor.ServiceDescriptor, 1), // unblock with buffered channel
opts: &ProviderOption{DynamicGoEnabled: true},
parseMode: parseMode,
goTagOpt: tOpts.goTag,
serviceName: tOpts.serviceName,
}
mainIDLContent, ok := includes[mainIDLPath]
if !ok {
return nil, fmt.Errorf("miss main IDL content for main IDL path: %s", mainIDLPath)
}

svc, err := newServiceDescriptorFromContent(mainIDLPath, mainIDLContent, includes, true, parseMode, tOpts.goTag)
svc, err := newServiceDescriptorFromContent(mainIDLPath, mainIDLContent, includes, true, parseMode, tOpts.goTag, tOpts.serviceName)
if err != nil {
return nil, err
}

p.newDynamicGoDsc(svc, mainIDLPath, mainIDLContent, includes, parseMode, tOpts.goTag)
p.newDynamicGoDsc(svc, mainIDLPath, mainIDLContent, includes, parseMode, tOpts.goTag, tOpts.serviceName)

p.svcs <- svc
return p, nil
Expand All @@ -391,13 +403,16 @@ func (p *ThriftContentWithAbsIncludePathProvider) UpdateIDL(mainIDLPath string,
if p.goTagOpt != nil {
parseOpts = append(parseOpts, thrift.WithGoTagDisabled(p.goTagOpt.isGoTagAliasDisabled))
}
if p.serviceName != "" {
parseOpts = append(parseOpts, thrift.WithIDLServiceName(p.serviceName))
}
svc, err = thrift.Parse(tree, p.parseMode, parseOpts...)
if err != nil {
return err
}

if p.opts.DynamicGoEnabled {
p.newDynamicGoDsc(svc, mainIDLPath, mainIDLContent, includes, p.parseMode, p.goTagOpt)
p.newDynamicGoDsc(svc, mainIDLPath, mainIDLContent, includes, p.parseMode, p.goTagOpt, p.serviceName)
}

// drain the channel
Expand Down Expand Up @@ -430,8 +445,8 @@ func (p *ThriftContentWithAbsIncludePathProvider) Option() ProviderOption {
return *p.opts
}

func (p *ThriftContentWithAbsIncludePathProvider) newDynamicGoDsc(svc *descriptor.ServiceDescriptor, path, content string, includes map[string]string, parseMode thrift.ParseMode, goTag *goTagOption) {
if err := newDynamicGoDscFromContent(svc, path, content, includes, true, parseMode, goTag); err != nil {
func (p *ThriftContentWithAbsIncludePathProvider) newDynamicGoDsc(svc *descriptor.ServiceDescriptor, path, content string, includes map[string]string, parseMode thrift.ParseMode, goTag *goTagOption, serviceName string) {
if err := newDynamicGoDscFromContent(svc, path, content, includes, true, parseMode, goTag, serviceName); err != nil {
p.opts.DynamicGoEnabled = false
}
}
Expand All @@ -457,7 +472,7 @@ func getDynamicGoParseMode(parseMode thrift.ParseMode) (meta.ParseServiceMode, e
}
}

func newServiceDescriptorFromContent(path, content string, includes map[string]string, isAbsIncludePath bool, parseMode thrift.ParseMode, goTagOpt *goTagOption) (*descriptor.ServiceDescriptor, error) {
func newServiceDescriptorFromContent(path, content string, includes map[string]string, isAbsIncludePath bool, parseMode thrift.ParseMode, goTagOpt *goTagOption, serviceName string) (*descriptor.ServiceDescriptor, error) {
tree, err := ParseContent(path, content, includes, isAbsIncludePath)
if err != nil {
return nil, err
Expand All @@ -466,21 +481,24 @@ func newServiceDescriptorFromContent(path, content string, includes map[string]s
if goTagOpt != nil {
parseOpts = append(parseOpts, thrift.WithGoTagDisabled(goTagOpt.isGoTagAliasDisabled))
}
if serviceName != "" {
parseOpts = append(parseOpts, thrift.WithIDLServiceName(serviceName))
}
svc, err := thrift.Parse(tree, parseMode, parseOpts...)
if err != nil {
return nil, err
}
return svc, nil
}

func newDynamicGoDscFromContent(svc *descriptor.ServiceDescriptor, path, content string, includes map[string]string, isAbsIncludePath bool, parseMode thrift.ParseMode, goTag *goTagOption) error {
func newDynamicGoDscFromContent(svc *descriptor.ServiceDescriptor, path, content string, includes map[string]string, isAbsIncludePath bool, parseMode thrift.ParseMode, goTag *goTagOption, serviceName string) error {
handleGoTagForDynamicGo(goTag)
// ServiceDescriptor of dynamicgo
dParseMode, err := getDynamicGoParseMode(parseMode)
if err != nil {
return err
}
dOpts := dthrift.Options{EnableThriftBase: true, ParseServiceMode: dParseMode, UseDefaultValue: true, SetOptionalBitmap: true}
dOpts := dthrift.Options{EnableThriftBase: true, ParseServiceMode: dParseMode, UseDefaultValue: true, SetOptionalBitmap: true, ServiceName: serviceName}
dsvc, err := dOpts.NewDescritorFromContent(context.Background(), path, content, includes, isAbsIncludePath)
if err != nil {
klog.CtxWarnf(context.Background(), "KITEX: failed to get dynamicgo service descriptor, fall back to the original way, error=%s", err)
Expand Down
Loading

0 comments on commit b7777a2

Please sign in to comment.