github.com/cloudwego/kitex@v0.9.0/client/genericclient/client.go (about) 1 /* 2 * Copyright 2021 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // Package genericclient ... 18 package genericclient 19 20 import ( 21 "context" 22 "runtime" 23 24 "github.com/cloudwego/kitex/client" 25 "github.com/cloudwego/kitex/client/callopt" 26 "github.com/cloudwego/kitex/pkg/generic" 27 "github.com/cloudwego/kitex/pkg/serviceinfo" 28 ) 29 30 var _ Client = &genericServiceClient{} 31 32 // NewClient create a generic client 33 func NewClient(destService string, g generic.Generic, opts ...client.Option) (Client, error) { 34 svcInfo := generic.ServiceInfo(g.PayloadCodecType()) 35 return NewClientWithServiceInfo(destService, g, svcInfo, opts...) 36 } 37 38 // NewClientWithServiceInfo create a generic client with serviceInfo 39 func NewClientWithServiceInfo(destService string, g generic.Generic, svcInfo *serviceinfo.ServiceInfo, opts ...client.Option) (Client, error) { 40 var options []client.Option 41 options = append(options, client.WithGeneric(g)) 42 options = append(options, client.WithDestService(destService)) 43 options = append(options, opts...) 44 45 kc, err := client.NewClient(svcInfo, options...) 46 if err != nil { 47 return nil, err 48 } 49 cli := &genericServiceClient{ 50 kClient: kc, 51 g: g, 52 } 53 runtime.SetFinalizer(cli, (*genericServiceClient).Close) 54 55 svcInfo.GenericMethod = func(name string) serviceinfo.MethodInfo { 56 m := svcInfo.Methods[serviceinfo.GenericMethod] 57 n, err := g.GetMethod(nil, name) 58 if err != nil { 59 return m 60 } 61 return &methodInfo{ 62 MethodInfo: m, 63 oneway: n.Oneway, 64 } 65 } 66 67 return cli, nil 68 } 69 70 // methodInfo is a wrapper to update the oneway flag of a service.MethodInfo. 71 type methodInfo struct { 72 serviceinfo.MethodInfo 73 oneway bool 74 } 75 76 func (m *methodInfo) OneWay() bool { 77 return m.oneway 78 } 79 80 // Client generic client 81 type Client interface { 82 generic.Closer 83 84 // GenericCall generic call 85 GenericCall(ctx context.Context, method string, request interface{}, callOptions ...callopt.Option) (response interface{}, err error) 86 } 87 88 type genericServiceClient struct { 89 kClient client.Client 90 g generic.Generic 91 } 92 93 func (gc *genericServiceClient) GenericCall(ctx context.Context, method string, request interface{}, callOptions ...callopt.Option) (response interface{}, err error) { 94 ctx = client.NewCtxWithCallOptions(ctx, callOptions) 95 var _args generic.Args 96 _args.Method = method 97 _args.Request = request 98 mt, err := gc.g.GetMethod(request, method) 99 if err != nil { 100 return nil, err 101 } 102 if mt.Oneway { 103 return nil, gc.kClient.Call(ctx, mt.Name, &_args, nil) 104 } 105 var _result generic.Result 106 if err = gc.kClient.Call(ctx, mt.Name, &_args, &_result); err != nil { 107 return 108 } 109 return _result.GetSuccess(), nil 110 } 111 112 func (gc *genericServiceClient) Close() error { 113 // no need a finalizer anymore 114 runtime.SetFinalizer(gc, nil) 115 116 // Notice: don't need to close kClient because finalizer will close it. 117 return gc.g.Close() 118 }