Skip to content

Commit

Permalink
feat: add include path for idl (#14)
Browse files Browse the repository at this point in the history
* feat: add include path for idl

* feat: add include path for idl

* doc: add include path for idl

* doc: add include path for idl
  • Loading branch information
Zzhiter authored Oct 24, 2024
1 parent 0c00dd2 commit b27183c
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 16 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Output:
- `-help` or `-h`: Outputs the usage instructions.
- `-type` or `-t`: Specifies the IDL type: thrift or protobuf. It supports inference based on the IDL file type. The default is thrift..
- `-idl-path` or `-p`: Specifies the path to the IDL file.
- `-include-path`: Add a search path for the IDL. Multiple paths can be added and will be searched in the order they are added.
- `-method` or `-m`: Required, specifies the method name in the format IDLServiceName/MethodName or just MethodName. When the server side has MultiService mode enabled, IDLServiceName must be specified, and the transport protocol must be TTHeader or TTHeaderFramed.
- `-file` or `-f`: Specifies the input file path, which must be in JSON format.
- `-data` or `-d`: Specifies the data to be sent, in JSON string format.
Expand All @@ -118,6 +119,7 @@ Output:
- `-meta`: Specifies one-way metadata passed to the server. Multiple can be specified, in the format key=value.
- `-meta-persistent`: Specifies persistent metadata passed to the server. Multiple can be specified, in the format key=value.
- `-meta-backward`: Enables receiving backward metadata (Backward) returned by the server.
- `-q`: Only output JSON response, no other information.
- `-verbose` or `-v`: Enables verbose mode for more detailed output information.

### Detailed Description
Expand Down
2 changes: 2 additions & 0 deletions README_cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ kitexcall -idl-path echo.thrift -m echo -d '{"message": "hello"}' -e 127.0.0.1:9
- `-help``-h`:输出使用说明。
- `-type``-t`:指定 IDL 类型:`thrift``protobuf`,支持通过 IDL 文件类型推测,默认是 `thrift`
- `-idl-path``-p`:指定 IDL 文件的路径。
- `-include-path`:添加一个 IDL 里 include 的其他文件的搜索路径。支持添加多个,会按照添加的路径顺序搜索。
- `-method``-m`:必选,指定方法名,格式为 `IDLServiceName/MethodName` 或仅为 `MethodName`。当 server 端开启了 MultiService 模式时,必须指定 `IDLServiceName`,同时指定传输协议为 TTHeader 或 TTHeaderFramed 。
- `-file``-f`:指定输入文件路径,必须是 JSON 格式。
- `-data``-d`:指定要发送的数据,格式为 JSON 字符串。
Expand All @@ -120,6 +121,7 @@ kitexcall -idl-path echo.thrift -m echo -d '{"message": "hello"}' -e 127.0.0.1:9
- `-meta`:指定传递给 server 的单跳透传元信息。可以指定多个,格式为 key=value。
- `-meta-persistent`:指定传递给 server 的持续透传元信息。可以指定多个,格式为 key=value。
- `-meta-backward`:启用从服务器接收反向透传元信息。
- `-q`: 只输出Json响应,不输出其他提示信息。
- `-verbose``-v`:启用详细模式。

### 详细描述
Expand Down
89 changes: 81 additions & 8 deletions internal/test/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"encoding/json"
"errors"
"net"
"os"
"path/filepath"
"testing"
"time"

Expand All @@ -38,14 +40,17 @@ import (
)

var (
thriftGenericServer server.Server
pbGenericServer server.Server
bizErrorGenericServer server.Server
thriftServerHost = "127.0.0.1:9919"
pbServerHostPort = "127.0.0.1:9199"
bizErrorServerHost = "127.0.0.1:9109"
pbFilePath = "./example_service.proto"
thriftFilePath = "./example_service.thrift"
thriftGenericServer server.Server
pbGenericServer server.Server
bizErrorGenericServer server.Server
thriftGenericServerWithImportPath server.Server
thriftServerHost = "127.0.0.1:9919"
pbServerHostPort = "127.0.0.1:9199"
bizErrorServerHost = "127.0.0.1:9109"
pbFilePath = "./example_service.proto"
thriftFilePath = "./example_service.thrift"
example2ServerHost = "127.0.0.1:9100"
example2FilePath = "./example2.thrift"
)

func InitPbGenericServer() {
Expand Down Expand Up @@ -100,6 +105,30 @@ func InitThriftGenericServer() {
WaitServerStart(thriftServerHost)
}

func InitThriftGenericServerWithImportPath() {
p, err := generic.NewThriftFileProvider(example2FilePath, "./idl")
if err != nil {
panic(err)
}
g, err := generic.JSONThriftGeneric(p)
if err != nil {
panic(err)
}

go func() {
addr, _ := net.ResolveTCPAddr("tcp", example2ServerHost)
klog.Infof("Starting Example2 service on %s", addr.String())

thriftGenericServerWithImportPath = genericserver.NewServer(new(GenericServiceImpl), g, server.WithServiceAddr(addr))

if err := thriftGenericServerWithImportPath.Run(); err != nil {
klog.Fatalf("Failed to run Example2 service: %v", err)
}
}()

WaitServerStart(example2ServerHost)
}

// WaitServerStart waits for server to start for at most 1 second
func WaitServerStart(addr string) {
for begin := time.Now(); time.Since(begin) < time.Second; {
Expand Down Expand Up @@ -292,3 +321,47 @@ func TestBizErrorGenericServer_invokeRPC(t *testing.T) {
t.Errorf("Expected BizMessage %s, got %s", expectedMessage, bizErr.BizMessage())
}
}

func TestExample2Service_withImportPath(t *testing.T) {
InitThriftGenericServerWithImportPath()
defer thriftGenericServerWithImportPath.Stop()

currentPath, _ := os.Getwd()
includePath := filepath.Join(currentPath, "idl")

conf := &config.Config{
Type: config.Thrift,
Endpoint: []string{example2ServerHost},
IDLPath: example2FilePath,
IDLServiceName: "Example2Service",
Method: "Example2Method",
Data: "{\"Msg\": \"hello\", \"User\": {\"UserID\": \"123\", \"UserName\": \"Alice\", \"Age\": 25}}",
Transport: config.TTHeader,
MetaBackward: true,
IncludePath: []string{includePath},
}

cli, err := client.InvokeRPC(conf)
if err != nil {
t.Fatalf("InvokeRPC failed: %v", err)
}

resp := cli.GetResponse()
if resp == nil {
t.Fatalf("Response is nil")
}

expectedResponse := `{"Msg":"world", "BaseResp": {"StatusCode": 0, "StatusMessage": ""}}`

var serverData, expectedData interface{}
json.Unmarshal([]byte(resp.(string)), &serverData)
json.Unmarshal([]byte(expectedResponse), &expectedData)
DeepEqual(t, serverData, expectedData)

// MetaBackward
if conf.MetaBackward {
if res := cli.GetMetaBackward(); res == nil {
t.Errorf("Expected meta backward not found in response")
}
}
}
34 changes: 34 additions & 0 deletions internal/test/example2.thrift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2024 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 kitex.test.server

include "common.thrift"

// Request data for Example2Service
struct Example2Req {
1: required string Msg,
2: required common.UserData User,
}

// Response for Example2Service
struct Example2Resp {
1: required string Msg,
2: required common.CommonResponse BaseResp,
}

// Service definition that uses imported common types
service Example2Service {
Example2Resp Example2Method(1: Example2Req req),
}
29 changes: 29 additions & 0 deletions internal/test/idl/common.thrift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2024 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 kitex.test.common

// Commonly shared struct in multiple services
struct CommonResponse {
1: string StatusMessage = "",
2: i32 StatusCode = 0,
3: optional map<string, string> Extra,
}

// Common data shared across services
struct UserData {
1: string UserID,
2: string UserName,
3: i32 Age,
}
25 changes: 18 additions & 7 deletions pkg/argparse/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ func NewArgument() *Argument {
}
}

type EndpointList []string
type StringList []string

func (e *EndpointList) String() string {
return strings.Join(*e, ",")
func (s *StringList) String() string {
return strings.Join(*s, ",")
}

func (e *EndpointList) Set(value string) error {
*e = append(*e, value)
func (s *StringList) Set(value string) error {
*s = append(*s, value)
return nil
}

Expand Down Expand Up @@ -90,8 +90,8 @@ func (a *Argument) buildFlags() *flag.FlagSet {
f.StringVar(&a.Data, "data", "", "Specify the data to be sent as a JSON formatted string.")
f.StringVar(&a.Data, "d", "", "Specify the data to be sent as a JSON formatted string. (shorthand)")

f.Var((*EndpointList)(&a.Endpoint), "endpoint", "Specify the server endpoints. Can be repeated.")
f.Var((*EndpointList)(&a.Endpoint), "e", "Specify the server endpoints. Can be repeated. (shorthand)")
f.Var((*StringList)(&a.Endpoint), "endpoint", "Specify the server endpoints. Can be repeated.")
f.Var((*StringList)(&a.Endpoint), "e", "Specify the server endpoints. Can be repeated. (shorthand)")

f.BoolVar(&a.Verbose, "verbose", false, "Enable verbose mode.")
f.BoolVar(&a.Verbose, "v", false, "Enable verbose mode. (shorthand)")
Expand All @@ -109,6 +109,8 @@ func (a *Argument) buildFlags() *flag.FlagSet {

f.BoolVar(&a.Quiet, "quiet", false, "Enable only print rpc response.")

f.Var((*StringList)(&a.IncludePath), "include-path", "Specify additional paths for imported IDL files. Can be repeated.")

return f
}

Expand Down Expand Up @@ -242,6 +244,14 @@ func (a *Argument) checkIDL() error {
return errors.New(errors.ArgParseError, "IDL file does not exist")
}

if a.IncludePath != nil {
for _, path := range a.IncludePath {
if _, err := os.Stat(path); os.IsNotExist(err) {
return errors.New(errors.ArgParseError, "Include path does not exist")
}
}
}

switch a.Type {
case "thrift", "protobuf":
case "unknown":
Expand Down Expand Up @@ -282,6 +292,7 @@ func (a *Argument) BuildConfig() *config.Config {
MetaBackward: a.MetaBackward,
BizError: a.BizError,
Quiet: a.Quiet,
IncludePath: a.IncludePath,
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/client/generic_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ func NewThriftGeneric() *ThriftGeneric {

func (c *ThriftGeneric) Init(Conf *config.Config) error {
// Waiting for server reflection
p, err := generic.NewThriftFileProvider(Conf.IDLPath)
p, err := generic.NewThriftFileProvider(Conf.IDLPath, Conf.IncludePath...)
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type Config struct {
MetaBackward bool
BizError bool
Quiet bool
IncludePath []string
}

type ConfigBuilder interface {
Expand Down

0 comments on commit b27183c

Please sign in to comment.