gencall.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. package gen
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "path/filepath"
  7. "strings"
  8. "github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
  9. "github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
  10. "github.com/tal-tech/go-zero/tools/goctl/util"
  11. )
  12. const (
  13. callTemplateText = `{{.head}}
  14. //go:generate mockgen -destination ./{{.name}}_mock.go -package {{.filePackage}} -source $GOFILE
  15. package {{.filePackage}}
  16. import (
  17. "context"
  18. {{.package}}
  19. "github.com/tal-tech/go-zero/core/jsonx"
  20. "github.com/tal-tech/go-zero/zrpc"
  21. )
  22. type (
  23. {{.serviceName}} interface {
  24. {{.interface}}
  25. }
  26. default{{.serviceName}} struct {
  27. cli zrpc.Client
  28. }
  29. )
  30. func New{{.serviceName}}(cli zrpc.Client) {{.serviceName}} {
  31. return &default{{.serviceName}}{
  32. cli: cli,
  33. }
  34. }
  35. {{.functions}}
  36. `
  37. callTemplateTypes = `{{.head}}
  38. package {{.filePackage}}
  39. import "errors"
  40. var errJsonConvert = errors.New("json convert error")
  41. {{.types}}
  42. `
  43. callInterfaceFunctionTemplate = `{{if .hasComment}}{{.comment}}
  44. {{end}}{{.method}}(ctx context.Context,in *{{.pbRequest}}) (*{{.pbResponse}},error)`
  45. callFunctionTemplate = `
  46. {{if .hasComment}}{{.comment}}{{end}}
  47. func (m *default{{.rpcServiceName}}) {{.method}}(ctx context.Context,in *{{.pbRequest}}) (*{{.pbResponse}}, error) {
  48. var request {{.package}}.{{.pbRequest}}
  49. bts, err := jsonx.Marshal(in)
  50. if err != nil {
  51. return nil, errJsonConvert
  52. }
  53. err = jsonx.Unmarshal(bts, &request)
  54. if err != nil {
  55. return nil, errJsonConvert
  56. }
  57. client := {{.package}}.New{{.rpcServiceName}}Client(m.cli.Conn())
  58. resp, err := client.{{.method}}(ctx, &request)
  59. if err != nil{
  60. return nil, err
  61. }
  62. var ret {{.pbResponse}}
  63. bts, err = jsonx.Marshal(resp)
  64. if err != nil{
  65. return nil, errJsonConvert
  66. }
  67. err = jsonx.Unmarshal(bts, &ret)
  68. if err != nil{
  69. return nil, errJsonConvert
  70. }
  71. return &ret, nil
  72. }
  73. `
  74. )
  75. func (g *defaultRpcGenerator) genCall() error {
  76. file := g.ast
  77. if len(file.Service) == 0 {
  78. return nil
  79. }
  80. if len(file.Service) > 1 {
  81. return fmt.Errorf("we recommend only one service in a proto, currently %d", len(file.Service))
  82. }
  83. typeCode, err := file.GenTypesCode()
  84. if err != nil {
  85. return err
  86. }
  87. service := file.Service[0]
  88. callPath := filepath.Join(g.dirM[dirTarget], service.Name.Lower())
  89. if err = util.MkdirIfNotExist(callPath); err != nil {
  90. return err
  91. }
  92. pbPkg := file.Package
  93. remotePackage := fmt.Sprintf(`%v "%v"`, pbPkg, g.mustGetPackage(dirPb))
  94. filename := filepath.Join(callPath, "types.go")
  95. head := util.GetHead(g.Ctx.ProtoSource)
  96. err = util.With("types").GoFmt(true).Parse(callTemplateTypes).SaveTo(map[string]interface{}{
  97. "head": head,
  98. "filePackage": service.Name.Lower(),
  99. "pbPkg": pbPkg,
  100. "serviceName": g.Ctx.ServiceName.Title(),
  101. "lowerStartServiceName": g.Ctx.ServiceName.UnTitle(),
  102. "types": typeCode,
  103. }, filename, true)
  104. if err != nil {
  105. return err
  106. }
  107. _, err = exec.LookPath("mockgen")
  108. mockGenInstalled := err == nil
  109. filename = filepath.Join(callPath, fmt.Sprintf("%s.go", service.Name.Lower()))
  110. functions, err := g.getFuncs(service)
  111. if err != nil {
  112. return err
  113. }
  114. iFunctions, err := g.getInterfaceFuncs(service)
  115. if err != nil {
  116. return err
  117. }
  118. mockFile := filepath.Join(callPath, fmt.Sprintf("%s_mock.go", service.Name.Lower()))
  119. _ = os.Remove(mockFile)
  120. err = util.With("shared").GoFmt(true).Parse(callTemplateText).SaveTo(map[string]interface{}{
  121. "name": service.Name.Lower(),
  122. "head": head,
  123. "filePackage": service.Name.Lower(),
  124. "pbPkg": pbPkg,
  125. "package": remotePackage,
  126. "serviceName": service.Name.Title(),
  127. "functions": strings.Join(functions, "\n"),
  128. "interface": strings.Join(iFunctions, "\n"),
  129. }, filename, true)
  130. if err != nil {
  131. return err
  132. }
  133. // if mockgen is already installed, it will generate code of gomock for shared files
  134. // Deprecated: it will be removed
  135. if mockGenInstalled && g.Ctx.IsInGoEnv {
  136. _, _ = execx.Run(fmt.Sprintf("go generate %s", filename), "")
  137. }
  138. return nil
  139. }
  140. func (g *defaultRpcGenerator) getFuncs(service *parser.RpcService) ([]string, error) {
  141. file := g.ast
  142. pkgName := file.Package
  143. functions := make([]string, 0)
  144. for _, method := range service.Funcs {
  145. var comment string
  146. if len(method.Document) > 0 {
  147. comment = method.Document[0]
  148. }
  149. buffer, err := util.With("sharedFn").Parse(callFunctionTemplate).Execute(map[string]interface{}{
  150. "rpcServiceName": service.Name.Title(),
  151. "method": method.Name.Title(),
  152. "package": pkgName,
  153. "pbRequest": method.InType,
  154. "pbResponse": method.OutType,
  155. "hasComment": len(method.Document) > 0,
  156. "comment": comment,
  157. })
  158. if err != nil {
  159. return nil, err
  160. }
  161. functions = append(functions, buffer.String())
  162. }
  163. return functions, nil
  164. }
  165. func (g *defaultRpcGenerator) getInterfaceFuncs(service *parser.RpcService) ([]string, error) {
  166. functions := make([]string, 0)
  167. for _, method := range service.Funcs {
  168. var comment string
  169. if len(method.Document) > 0 {
  170. comment = method.Document[0]
  171. }
  172. buffer, err := util.With("interfaceFn").Parse(callInterfaceFunctionTemplate).Execute(
  173. map[string]interface{}{
  174. "hasComment": len(method.Document) > 0,
  175. "comment": comment,
  176. "method": method.Name.Title(),
  177. "pbRequest": method.InType,
  178. "pbResponse": method.OutType,
  179. })
  180. if err != nil {
  181. return nil, err
  182. }
  183. functions = append(functions, buffer.String())
  184. }
  185. return functions, nil
  186. }