Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(generic): add an option to specify an IDL service name to be parsed #1673

Merged
merged 5 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading